SlideShare una empresa de Scribd logo
1 de 62
@hpique
Android In-app Billing
        Demystified




       Hermés Piqué
         @hpique
Agenda

• In-app Billing Overview
• Google Play Billing Service
• Android Billing Library
• Security Best Practices
Top Grossing
is dominated
    by IAB
Freemium
 Digital goods
Virtual currency
 Subscriptions
User experience
In-app billing terms

• Powered by Google Wallet
• 30% of the sale price
• No refunds (kinda)
• Only for digital goods
• Flexible pricing (unlike iOS)
Agenda

• In-app Billing Overview
• Google Play Billing Service
• Android Billing Library
• Security Best Practices
Google Play Billing
       Service

• Google Play only
• Android 1.6 upwards (API level 4)
• Now at version 2 with subscriptions
  support
Product types
• In-app products
 •   Managed (per user account): premium, digital
     content

 •   Unmanaged: virtual currency, consumable virtual
     goods

• Subscriptions
 •   Monthly & yearly with free trials support
Pre-requisites

• Services
• AIDL
• BroadcastReceiver
• PendingIntent
Wait, there’s more

• SQLite
• Obfuscation
• Signature validation
• 57 pages of doc!
Architecture overview

  app
                Android
    IAB         Market
  requests
                 Server
IAB requests

• CHECK_BILLING_SUPPORTED
• REQUEST_PURCHASE
• GET_PURCHASE_INFORMATION
• CONFIRM_NOTIFICATIONS
• RESTORE_TRANSACTIONS
IAB requests
• MarketBillingService interface defined in an
  Android Interface Definition Language file
  (IMarketBillingService.aidl)
• IAB requests sent by single IPC method
  (sendBillingRequest()) of the interface
• Request type and parameters are sent as a
  Bundle
Binding to
          MarketBillingService
try {
  boolean bindResult = mContext.bindService(
    new Intent("com.android.vending.billing.MarketBillingService.BIND"), this,
    Context.BIND_AUTO_CREATE);
  if (bindResult) {
    Log.i(TAG, "Service bind successful.");
  } else {
    Log.e(TAG, "Could not bind to the MarketBillingService.");
  }
} catch (SecurityException e) {
  Log.e(TAG, "Security exception: " + e);
}


public void onServiceConnected(ComponentName name, IBinder service) {
  Log.i(TAG, "MarketBillingService connected.");
  mService = IMarketBillingService.Stub.asInterface(service);
}
Request bundle
           parameters
•   Shared

    •   BILLING_REQUEST: request type

    •   API_VERSION: “1” for in-app products, “2” for
        subscriptions

    •   PACKAGE_NAME: app package

•   Specific

    •   ITEM_ID, ITEM_TYPE, NONCE, NOTIFY_ID,
        DEVELOPER_PAYLOAD
Request bundle

protected Bundle makeRequestBundle(String method) {
  Bundle request = new Bundle();
  request.putString(BILLING_REQUEST, method);
  request.putInt(API_VERSION, 1);
  request.putString(PACKAGE_NAME, getPackageName());
  return request;
}
Making a request


Bundle request = makeRequestBundle("REQUEST_PURCHASE");
request.putString(ITEM_ID, mProductId);
Bundle response = mService.sendBillingRequest(request);
IAB responses

• The IAB service responds to every request
  with a synchronous response
• Followed by 0..N asynchronous responses
  depending of the request type
Synchronous responses
• RESPONSE_CODE: status information and
  error information about a request
• REQUEST_ID: used to match
  asynchronous responses with requests
• PURCHASE_INTENT: PendingIntent, which
  you use to launch the checkout activity
 •   REQUEST_PURCHASE only
Asynchronous
      responses
• Broadcast intents:
 • RESPONSE_CODE
 • IN_APP_NOTIFY
 • PURCHASE_STATE_CHANGED
Receiving async
                  responses
 public void onReceive(Context context, Intent intent) {
    String action = intent.getAction();
    if (ACTION_PURCHASE_STATE_CHANGED.equals(action)) {
      String signedData = intent.getStringExtra(INAPP_SIGNED_DATA);
      String signature = intent.getStringExtra(INAPP_SIGNATURE);
      // Do something with the signedData and the signature.
    } else if (ACTION_NOTIFY.equals(action)) {
      String notifyId = intent.getStringExtra(NOTIFICATION_ID);
      // Do something with the notifyId.
    } else if (ACTION_RESPONSE_CODE.equals(action)) {
      long requestId = intent.getLongExtra(INAPP_REQUEST_ID, -1);
      int responseCodeIndex = intent.getIntExtra(INAPP_RESPONSE_CODE,
        ResponseCode.RESULT_ERROR.ordinal());
      // Do something with the requestId and the responseCodeIndex.
    } else {
      Log.w(TAG, "unexpected action: " + action);
    }
  }
Check Billing
 Supported
Check Billing
               Supported
Parameters                     Shared
Sync response keys        RESPONSE_CODE
                             RESULT_OK
                     RESULT_BILLING_UNAVAILABLE
Response codes
                            RESULT_ERROR
                      RESULT_DEVELOPER_ERROR
Async response            RESPONSE_CODE
Request Purchase
Request Purchase
                                Shared
                               ITEM_ID
Parameters
                             ITEM_TYPE
                       DEVELOPER_PAYLOAD
                         RESPONSE_CODE
Sync response keys      PURCHASE_INTENT
                            REQUEST_ID
                            RESULT_OK
Response codes             RESULT_ERROR
                     RESULT_DEVELOPER_ERROR
                         RESPONSE_CODE
Async response
                          IN_APP_NOTIFY
Get Purchase
             Information
                               Shared
Parameters                    NONCE
                             NOTIFY_IDS
                          RESPONSE_CODE
Sync response keys
                            REQUEST_ID
                             RESULT_OK
Response codes             RESULT_ERROR
                      RESULT_DEVELOPER_ERROR
                          RESPONSE_CODE
Async response
                     PURCHASE_STATE_CHANGED
Purchase State Changed
          JSON
{ "nonce" : 1836535032137741465,
  "orders" :
    [{ "notificationId" : "android.test.purchased",
       "orderId" : "transactionId.android.test.purchased",
       "packageName" : "com.example.dungeons",
       "productId" : "android.test.purchased",
       "developerPayload" : "bGoa+V7g/yqDXvKRq",
       "purchaseTime" : 1290114783411,
       "purchaseState" : 0,
       "purchaseToken" : "rojeslcdyyiapnqcynkjyyjh" }]
}
JSON fields (1)
• nonce: to verify the integrity of the
  message
• notificationId: to match with
  IN_APP_NOTIFY
• orderId: Google Wallet order id
• packageName: your app package
JSON fields (2)
• productId: set in the Developer Console
• purchaseTime: time of purchase
• purchaseState: purchased, cancelled,
  refunded or expired
• purchaseToken: subscriptionId
• developerPayload: optional value
  provided in REQUEST_PURCHASE
Purchase states

• Purchased (0)
• Cancelled (1)
• Refunded (2)
• Expired (3): subscriptions only
Confirm Notifications
                              Shared
Parameters                   NONCE
                            NOTIFY_IDS
                         RESPONSE_CODE
Sync response keys
                           REQUEST_ID
                            RESULT_OK
Response codes            RESULT_ERROR
                     RESULT_DEVELOPER_ERROR
Async response           RESPONSE_CODE
Unsolicited In-app
       Notify
• Purchase when app is running in
  various devices
• Refunds
• Subscription expired (?)
Unsolicited In-app
     Notify
Restore Transactions
Restore Transactions
                                Basic
Parameters
                              NONCE
                          RESPONSE_CODE
Sync response keys
                            REQUEST_ID
                             RESULT_OK
Response codes             RESULT_ERROR
                      RESULT_DEVELOPER_ERROR
                          RESPONSE_CODE
Async response
                     PURCHASE_STATE_CHANGED
Security Controls


• Signed purchase data
• In-app notify nonces
Purchase State
   Changed Extras

• inapp_signed_data: Signed JSON
  string (unencrypted)
• inapp_signature: Use the Google
  Play public key to validate
IAB limitations

• No API for product details & price
• To fully test you need to pay for real
• Sometimes async messages are really async
Obligatory image of Justin Bieber to wake you up
Agenda

• In-app Billing Overview
• Google Play Billing Service
• Android Billing Library
• Security Best Practices
requestPurchase("com.example.item");
Android Billing Library

     tiny.cc/android-billing


• Open-source on github
• “Better than starting from scratch”™
Features

• Full Android IAB Service implementation
• Auto-confirmations
• Obfuscated purchase database
• Implements security best practices
• Half-decent unit testing coverage
Overview

• BillingController
• IBillingObserver
• BillingController.IConfiguration
• ISignatureValidator
Overview
Check Billing
                Supported
"   @Override
"   public void onCreate(Bundle savedInstanceState) {
"   " // ...
"   " BillingController.registerObserver(mBillingObserver);
"   " BillingController.checkBillingSupported(this);
"   " // ...
"   }

"   public void onBillingChecked(boolean supported) {
"   " if (!supported) {
"   " " showDialog(DIALOG_BILLING_NOT_SUPPORTED_ID);
"   " }
"   }
Request Purchase
BillingController.requestPurchase(this, productId);


@Override
public void onPurchaseIntent(String itemId, PendingIntent purchaseIntent) {
	 BillingController.startPurchaseIntent(activity, purchaseIntent, null);
}

@Override
public void onRequestPurchaseResponse(String itemId, ResponseCode response) {

}

@Override
public void onPurchaseStateChanged(String itemId, Order order) {

}
Restore Transactions
if (!mBillingObserver.isTransactionsRestored()) {
	 BillingController.restoreTransactions(this);
	 Toast.makeText(this, R.string.restoring_transactions,
Toast.LENGTH_LONG).show();
}

@Override
public void onTransactionsRestored() {
	 final SharedPreferences preferences =
PreferenceManager.getDefaultSharedPreferences(activity);
	 final Editor editor = preferences.edit();
	 editor.putBoolean(KEY_TRANSACTIONS_RESTORED, true);
	 editor.commit();
}
Suggested
implementation
AndroidManifest.xml
    <!-- Add this permission to your manifest -->
    <uses-permission android:name="com.android.vending.BILLING" />
    <application>
    	 <!-- Add this service and receiver to your application -->
        <service android:name="net.robotmedia.billing.BillingService" />
        <receiver android:name="net.robotmedia.billing.BillingReceiver">
            <intent-filter>
                <action android:name="com.android.vending.billing.IN_APP_NOTIFY" />
                <action android:name="com.android.vending.billing.RESPONSE_CODE" />
                <action
android:name="com.android.vending.billing.PURCHASE_STATE_CHANGED" />
            </intent-filter>
        </receiver>
    </application>
Set Configuration
	   public void onCreate() {
	   	 super.onCreate();
	   	 BillingController.setDebug(true);
	   	 BillingController.setConfiguration(new BillingController.IConfiguration() {
	   	 	
	   	 	 @Override
	   	 	 public byte[] getObfuscationSalt() {
	   	 	 	 return new byte[] {41, -90, -116, -41, 66, -53, 122, -110, -127, -96, -88, 77, 127
	   	 	 }

	   	   	 @Override
	   	   	 public String getPublicKey() {
	   	   	 	 return "your public key here";
	   	   	 }
	   	   });
	   }
Agenda

• In-app Billing Overview
• Google Play Billing Service
• Android Billing Library
• Security Best Practices
Best Practices

• Random nonces
• Obfuscate purchase data
• Embedding public key
• Code obfuscation
• Server-side signature validation
Random nonces

• Sent with
  GET_PURCHASE_INFORMATION and
  RESTORE_TRANSACTION requests
• Handled by ABL
• Server-side nonce generation & verification
  not supported by ABL (but really?)
Obfuscate purchase data

 • Do not store purchase data plainly
 • Handled by ABL
 • Uses salt, installation id, device id and app id
   to perform obfuscation
Embedding public key


• Do not embed the public key plainly
• Only embed the public key if you can’t
  perform server-side signature validation
Code obfuscation

• Obfuscate your app code to make it harder
  to hack
• Problem: ABL is open-source!
• Use ProGuard and consider making
  changes to the ABL code
Server-side validation
• Perform the signature validation on a
  server
• Supported by ABL
• Provide your own ISignatureValidator;
  validation is performed with AsyncTask
• Return null on IConfiguration.getKey
Thanks!

Más contenido relacionado

Similar a Android in-app billing @ Google DevFest Barcelona 2012

Android In-app Billing @ Droidcon Murcia
Android In-app Billing @ Droidcon MurciaAndroid In-app Billing @ Droidcon Murcia
Android In-app Billing @ Droidcon MurciaRobot Media
 
IAP auto renewable in practice
IAP auto renewable  in practiceIAP auto renewable  in practice
IAP auto renewable in practiceHokila Jan
 
2012 SVCodeCamp: In App Payments with HTML5
2012 SVCodeCamp: In App Payments with HTML52012 SVCodeCamp: In App Payments with HTML5
2012 SVCodeCamp: In App Payments with HTML5Jonathan LeBlanc
 
AdVenture Capitalist Post-Mortem
AdVenture Capitalist Post-MortemAdVenture Capitalist Post-Mortem
AdVenture Capitalist Post-MortemPlayFab, Inc.
 
HTML5 Gaming Payment Platforms
HTML5 Gaming Payment PlatformsHTML5 Gaming Payment Platforms
HTML5 Gaming Payment PlatformsJonathan LeBlanc
 
API Product Management and Strategy
API Product Management and StrategyAPI Product Management and Strategy
API Product Management and Strategyadritab
 
INTEGRATED SHOPPING ASSISTANCE WITH FREDGE AND MOBILE
INTEGRATED SHOPPING ASSISTANCE WITH FREDGE AND MOBILEINTEGRATED SHOPPING ASSISTANCE WITH FREDGE AND MOBILE
INTEGRATED SHOPPING ASSISTANCE WITH FREDGE AND MOBILERajesh Roky
 
iOS In-App-Purchase verifying receipt locally in Swift
iOS In-App-Purchase verifying receipt locally in SwiftiOS In-App-Purchase verifying receipt locally in Swift
iOS In-App-Purchase verifying receipt locally in SwiftKaz Yoshikawa
 
Selling Physical GoodsThrough Apps & Other Monetization Strategies (MBL306) |...
Selling Physical GoodsThrough Apps & Other Monetization Strategies (MBL306) |...Selling Physical GoodsThrough Apps & Other Monetization Strategies (MBL306) |...
Selling Physical GoodsThrough Apps & Other Monetization Strategies (MBL306) |...Amazon Web Services
 
App Store Subscriptions - Condensed Edition
App Store Subscriptions - Condensed EditionApp Store Subscriptions - Condensed Edition
App Store Subscriptions - Condensed EditionMark Pavlidis
 
Big commerce app development
Big commerce app developmentBig commerce app development
Big commerce app developmentNascenia IT
 
APIDays Sydney
APIDays SydneyAPIDays Sydney
APIDays SydneyBraintree
 
Interconnect Mobile Application Development on Bluemix!!
Interconnect Mobile Application Development on Bluemix!!Interconnect Mobile Application Development on Bluemix!!
Interconnect Mobile Application Development on Bluemix!!Todd Kaplinger
 

Similar a Android in-app billing @ Google DevFest Barcelona 2012 (20)

Android In-app Billing @ Droidcon Murcia
Android In-app Billing @ Droidcon MurciaAndroid In-app Billing @ Droidcon Murcia
Android In-app Billing @ Droidcon Murcia
 
IAP auto renewable in practice
IAP auto renewable  in practiceIAP auto renewable  in practice
IAP auto renewable in practice
 
2012 SVCodeCamp: In App Payments with HTML5
2012 SVCodeCamp: In App Payments with HTML52012 SVCodeCamp: In App Payments with HTML5
2012 SVCodeCamp: In App Payments with HTML5
 
AdVenture Capitalist Post-Mortem
AdVenture Capitalist Post-MortemAdVenture Capitalist Post-Mortem
AdVenture Capitalist Post-Mortem
 
HTML5 Gaming Payment Platforms
HTML5 Gaming Payment PlatformsHTML5 Gaming Payment Platforms
HTML5 Gaming Payment Platforms
 
Samsung IAP SDK
Samsung IAP SDKSamsung IAP SDK
Samsung IAP SDK
 
API Product Management and Strategy
API Product Management and StrategyAPI Product Management and Strategy
API Product Management and Strategy
 
INTEGRATED SHOPPING ASSISTANCE WITH FREDGE AND MOBILE
INTEGRATED SHOPPING ASSISTANCE WITH FREDGE AND MOBILEINTEGRATED SHOPPING ASSISTANCE WITH FREDGE AND MOBILE
INTEGRATED SHOPPING ASSISTANCE WITH FREDGE AND MOBILE
 
In App Purchases
In  App  PurchasesIn  App  Purchases
In App Purchases
 
iOS In-App-Purchase verifying receipt locally in Swift
iOS In-App-Purchase verifying receipt locally in SwiftiOS In-App-Purchase verifying receipt locally in Swift
iOS In-App-Purchase verifying receipt locally in Swift
 
Selling Physical GoodsThrough Apps & Other Monetization Strategies (MBL306) |...
Selling Physical GoodsThrough Apps & Other Monetization Strategies (MBL306) |...Selling Physical GoodsThrough Apps & Other Monetization Strategies (MBL306) |...
Selling Physical GoodsThrough Apps & Other Monetization Strategies (MBL306) |...
 
Fire up your mobile app!
Fire up your mobile app!Fire up your mobile app!
Fire up your mobile app!
 
App Store Subscriptions - Condensed Edition
App Store Subscriptions - Condensed EditionApp Store Subscriptions - Condensed Edition
App Store Subscriptions - Condensed Edition
 
Shopify
ShopifyShopify
Shopify
 
Big commerce app development
Big commerce app developmentBig commerce app development
Big commerce app development
 
APIDays Sydney
APIDays SydneyAPIDays Sydney
APIDays Sydney
 
APIDays Sydney
APIDays SydneyAPIDays Sydney
APIDays Sydney
 
In-App Purchase API
In-App Purchase APIIn-App Purchase API
In-App Purchase API
 
Interconnect Mobile Application Development on Bluemix!!
Interconnect Mobile Application Development on Bluemix!!Interconnect Mobile Application Development on Bluemix!!
Interconnect Mobile Application Development on Bluemix!!
 
Workshop CQRS and DDD
Workshop CQRS and DDDWorkshop CQRS and DDD
Workshop CQRS and DDD
 

Último

What is Artificial Intelligence?????????
What is Artificial Intelligence?????????What is Artificial Intelligence?????????
What is Artificial Intelligence?????????blackmambaettijean
 
What is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfWhat is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfMounikaPolabathina
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxLoriGlavin3
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenHervé Boutemy
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxLoriGlavin3
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .Alan Dix
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxLoriGlavin3
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxLoriGlavin3
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxLoriGlavin3
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxhariprasad279825
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersNicole Novielli
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024Stephanie Beckett
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsPixlogix Infotech
 

Último (20)

What is Artificial Intelligence?????????
What is Artificial Intelligence?????????What is Artificial Intelligence?????????
What is Artificial Intelligence?????????
 
What is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfWhat is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdf
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache Maven
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptx
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptx
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software Developers
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and Cons
 

Android in-app billing @ Google DevFest Barcelona 2012

  • 2. Android In-app Billing Demystified Hermés Piqué @hpique
  • 3. Agenda • In-app Billing Overview • Google Play Billing Service • Android Billing Library • Security Best Practices
  • 5. Freemium Digital goods Virtual currency Subscriptions
  • 7. In-app billing terms • Powered by Google Wallet • 30% of the sale price • No refunds (kinda) • Only for digital goods • Flexible pricing (unlike iOS)
  • 8. Agenda • In-app Billing Overview • Google Play Billing Service • Android Billing Library • Security Best Practices
  • 9. Google Play Billing Service • Google Play only • Android 1.6 upwards (API level 4) • Now at version 2 with subscriptions support
  • 10. Product types • In-app products • Managed (per user account): premium, digital content • Unmanaged: virtual currency, consumable virtual goods • Subscriptions • Monthly & yearly with free trials support
  • 11. Pre-requisites • Services • AIDL • BroadcastReceiver • PendingIntent
  • 12. Wait, there’s more • SQLite • Obfuscation • Signature validation • 57 pages of doc!
  • 13. Architecture overview app Android IAB Market requests Server
  • 14. IAB requests • CHECK_BILLING_SUPPORTED • REQUEST_PURCHASE • GET_PURCHASE_INFORMATION • CONFIRM_NOTIFICATIONS • RESTORE_TRANSACTIONS
  • 15. IAB requests • MarketBillingService interface defined in an Android Interface Definition Language file (IMarketBillingService.aidl) • IAB requests sent by single IPC method (sendBillingRequest()) of the interface • Request type and parameters are sent as a Bundle
  • 16. Binding to MarketBillingService try {   boolean bindResult = mContext.bindService(     new Intent("com.android.vending.billing.MarketBillingService.BIND"), this,     Context.BIND_AUTO_CREATE);   if (bindResult) {     Log.i(TAG, "Service bind successful.");   } else {     Log.e(TAG, "Could not bind to the MarketBillingService.");   } } catch (SecurityException e) {   Log.e(TAG, "Security exception: " + e); } public void onServiceConnected(ComponentName name, IBinder service) {   Log.i(TAG, "MarketBillingService connected.");   mService = IMarketBillingService.Stub.asInterface(service); }
  • 17. Request bundle parameters • Shared • BILLING_REQUEST: request type • API_VERSION: “1” for in-app products, “2” for subscriptions • PACKAGE_NAME: app package • Specific • ITEM_ID, ITEM_TYPE, NONCE, NOTIFY_ID, DEVELOPER_PAYLOAD
  • 18. Request bundle protected Bundle makeRequestBundle(String method) {   Bundle request = new Bundle();   request.putString(BILLING_REQUEST, method);   request.putInt(API_VERSION, 1);   request.putString(PACKAGE_NAME, getPackageName());   return request; }
  • 19. Making a request Bundle request = makeRequestBundle("REQUEST_PURCHASE"); request.putString(ITEM_ID, mProductId); Bundle response = mService.sendBillingRequest(request);
  • 20. IAB responses • The IAB service responds to every request with a synchronous response • Followed by 0..N asynchronous responses depending of the request type
  • 21. Synchronous responses • RESPONSE_CODE: status information and error information about a request • REQUEST_ID: used to match asynchronous responses with requests • PURCHASE_INTENT: PendingIntent, which you use to launch the checkout activity • REQUEST_PURCHASE only
  • 22. Asynchronous responses • Broadcast intents: • RESPONSE_CODE • IN_APP_NOTIFY • PURCHASE_STATE_CHANGED
  • 23. Receiving async responses public void onReceive(Context context, Intent intent) {     String action = intent.getAction();     if (ACTION_PURCHASE_STATE_CHANGED.equals(action)) {       String signedData = intent.getStringExtra(INAPP_SIGNED_DATA);       String signature = intent.getStringExtra(INAPP_SIGNATURE);       // Do something with the signedData and the signature.     } else if (ACTION_NOTIFY.equals(action)) {       String notifyId = intent.getStringExtra(NOTIFICATION_ID);       // Do something with the notifyId.     } else if (ACTION_RESPONSE_CODE.equals(action)) {       long requestId = intent.getLongExtra(INAPP_REQUEST_ID, -1);       int responseCodeIndex = intent.getIntExtra(INAPP_RESPONSE_CODE,         ResponseCode.RESULT_ERROR.ordinal());       // Do something with the requestId and the responseCodeIndex.     } else {       Log.w(TAG, "unexpected action: " + action);     }   }
  • 25. Check Billing Supported Parameters Shared Sync response keys RESPONSE_CODE RESULT_OK RESULT_BILLING_UNAVAILABLE Response codes RESULT_ERROR RESULT_DEVELOPER_ERROR Async response RESPONSE_CODE
  • 27. Request Purchase Shared ITEM_ID Parameters ITEM_TYPE DEVELOPER_PAYLOAD RESPONSE_CODE Sync response keys PURCHASE_INTENT REQUEST_ID RESULT_OK Response codes RESULT_ERROR RESULT_DEVELOPER_ERROR RESPONSE_CODE Async response IN_APP_NOTIFY
  • 28. Get Purchase Information Shared Parameters NONCE NOTIFY_IDS RESPONSE_CODE Sync response keys REQUEST_ID RESULT_OK Response codes RESULT_ERROR RESULT_DEVELOPER_ERROR RESPONSE_CODE Async response PURCHASE_STATE_CHANGED
  • 29. Purchase State Changed JSON { "nonce" : 1836535032137741465, "orders" : [{ "notificationId" : "android.test.purchased", "orderId" : "transactionId.android.test.purchased", "packageName" : "com.example.dungeons", "productId" : "android.test.purchased", "developerPayload" : "bGoa+V7g/yqDXvKRq", "purchaseTime" : 1290114783411, "purchaseState" : 0, "purchaseToken" : "rojeslcdyyiapnqcynkjyyjh" }] }
  • 30. JSON fields (1) • nonce: to verify the integrity of the message • notificationId: to match with IN_APP_NOTIFY • orderId: Google Wallet order id • packageName: your app package
  • 31. JSON fields (2) • productId: set in the Developer Console • purchaseTime: time of purchase • purchaseState: purchased, cancelled, refunded or expired • purchaseToken: subscriptionId • developerPayload: optional value provided in REQUEST_PURCHASE
  • 32. Purchase states • Purchased (0) • Cancelled (1) • Refunded (2) • Expired (3): subscriptions only
  • 33. Confirm Notifications Shared Parameters NONCE NOTIFY_IDS RESPONSE_CODE Sync response keys REQUEST_ID RESULT_OK Response codes RESULT_ERROR RESULT_DEVELOPER_ERROR Async response RESPONSE_CODE
  • 34. Unsolicited In-app Notify • Purchase when app is running in various devices • Refunds • Subscription expired (?)
  • 37. Restore Transactions Basic Parameters NONCE RESPONSE_CODE Sync response keys REQUEST_ID RESULT_OK Response codes RESULT_ERROR RESULT_DEVELOPER_ERROR RESPONSE_CODE Async response PURCHASE_STATE_CHANGED
  • 38. Security Controls • Signed purchase data • In-app notify nonces
  • 39. Purchase State Changed Extras • inapp_signed_data: Signed JSON string (unencrypted) • inapp_signature: Use the Google Play public key to validate
  • 40.
  • 41. IAB limitations • No API for product details & price • To fully test you need to pay for real • Sometimes async messages are really async
  • 42. Obligatory image of Justin Bieber to wake you up
  • 43. Agenda • In-app Billing Overview • Google Play Billing Service • Android Billing Library • Security Best Practices
  • 45. Android Billing Library tiny.cc/android-billing • Open-source on github • “Better than starting from scratch”™
  • 46. Features • Full Android IAB Service implementation • Auto-confirmations • Obfuscated purchase database • Implements security best practices • Half-decent unit testing coverage
  • 47. Overview • BillingController • IBillingObserver • BillingController.IConfiguration • ISignatureValidator
  • 49. Check Billing Supported " @Override " public void onCreate(Bundle savedInstanceState) { " " // ... " " BillingController.registerObserver(mBillingObserver); " " BillingController.checkBillingSupported(this); " " // ... " } " public void onBillingChecked(boolean supported) { " " if (!supported) { " " " showDialog(DIALOG_BILLING_NOT_SUPPORTED_ID); " " } " }
  • 50. Request Purchase BillingController.requestPurchase(this, productId); @Override public void onPurchaseIntent(String itemId, PendingIntent purchaseIntent) { BillingController.startPurchaseIntent(activity, purchaseIntent, null); } @Override public void onRequestPurchaseResponse(String itemId, ResponseCode response) { } @Override public void onPurchaseStateChanged(String itemId, Order order) { }
  • 51. Restore Transactions if (!mBillingObserver.isTransactionsRestored()) { BillingController.restoreTransactions(this); Toast.makeText(this, R.string.restoring_transactions, Toast.LENGTH_LONG).show(); } @Override public void onTransactionsRestored() { final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity); final Editor editor = preferences.edit(); editor.putBoolean(KEY_TRANSACTIONS_RESTORED, true); editor.commit(); }
  • 53. AndroidManifest.xml <!-- Add this permission to your manifest --> <uses-permission android:name="com.android.vending.BILLING" /> <application> <!-- Add this service and receiver to your application --> <service android:name="net.robotmedia.billing.BillingService" /> <receiver android:name="net.robotmedia.billing.BillingReceiver"> <intent-filter> <action android:name="com.android.vending.billing.IN_APP_NOTIFY" /> <action android:name="com.android.vending.billing.RESPONSE_CODE" /> <action android:name="com.android.vending.billing.PURCHASE_STATE_CHANGED" /> </intent-filter> </receiver> </application>
  • 54. Set Configuration public void onCreate() { super.onCreate(); BillingController.setDebug(true); BillingController.setConfiguration(new BillingController.IConfiguration() { @Override public byte[] getObfuscationSalt() { return new byte[] {41, -90, -116, -41, 66, -53, 122, -110, -127, -96, -88, 77, 127 } @Override public String getPublicKey() { return "your public key here"; } }); }
  • 55. Agenda • In-app Billing Overview • Google Play Billing Service • Android Billing Library • Security Best Practices
  • 56. Best Practices • Random nonces • Obfuscate purchase data • Embedding public key • Code obfuscation • Server-side signature validation
  • 57. Random nonces • Sent with GET_PURCHASE_INFORMATION and RESTORE_TRANSACTION requests • Handled by ABL • Server-side nonce generation & verification not supported by ABL (but really?)
  • 58. Obfuscate purchase data • Do not store purchase data plainly • Handled by ABL • Uses salt, installation id, device id and app id to perform obfuscation
  • 59. Embedding public key • Do not embed the public key plainly • Only embed the public key if you can’t perform server-side signature validation
  • 60. Code obfuscation • Obfuscate your app code to make it harder to hack • Problem: ABL is open-source! • Use ProGuard and consider making changes to the ABL code
  • 61. Server-side validation • Perform the signature validation on a server • Supported by ABL • Provide your own ISignatureValidator; validation is performed with AsyncTask • Return null on IConfiguration.getKey

Notas del editor

  1. \n
  2. \n
  3. \n
  4. \n
  5. \n
  6. \n
  7. \n
  8. \n
  9. \n
  10. \n
  11. \n
  12. \n
  13. \n
  14. \n
  15. \n
  16. \n
  17. \n
  18. \n
  19. \n
  20. \n
  21. \n
  22. \n
  23. \n
  24. \n
  25. \n
  26. \n
  27. \n
  28. \n
  29. \n
  30. \n
  31. \n
  32. \n
  33. \n
  34. \n
  35. \n
  36. \n
  37. \n
  38. \n
  39. \n
  40. \n
  41. \n
  42. \n
  43. \n
  44. \n
  45. \n
  46. \n
  47. \n
  48. \n
  49. \n
  50. \n
  51. \n
  52. \n
  53. \n
  54. \n
  55. \n
  56. \n
  57. \n
  58. \n
  59. \n
  60. \n
  61. \n
  62. \n