Google I/O 2011: Evading Pirates and Stopping Vampires


Uploaded by GoogleDevelopers on 12.05.2011

Transcript:
Galpin: So the title of the presentation
is "Evading Pirates and Stopping Vampires
Using License Server, In-app Billing, and App Engine."
Now you might ask,
"Okay, what do these three things have in common?
License Server, In-app Billing, and App Engine."
And they're all technologies that we're providing
that allow you to take some form of your application
and put it into the Cloud.
In this case,
the way your application protects itself from pirates
as well as the way we validate that protection
is now all being put in some form or another in the Cloud.
But let's talk first about pirates.
So piracy is a reality on all platforms,
and really dedicated pirates aren't going to be stopped,
which is why this talk is not titled "Stopping Pirates,"
because we recognize that--
that, uh, ultimately people
are very, uh,
they're--they're-- ultimately people are--
are going to be very, very dedicated
to trying to--
to the craft of hacking.
But what we want to do
is not necessarily target these people.
Let them have fun.
But let's target these guys instead.
Yeah, we all know--
we all know what these pirates look like.
You know, the regular pirates are, you know--
have the eye patch, and they're green, and, you know, they--
but these guys here are the guys we really want
because these guys are our potential customers.
So why do stuff like make piracy a little inconvenient
or challenging or message that it's uncool?
You know, we can use the fact
that people are downloading our application as a marketing tool.
It doesn't necessarily have to be something
where someone comes up
and they just can't play anything
and they can't see anything.
That doesn't help us ultimately.
Um, we want to make sure that people recognize
that there's great content out there.
And of course, we want to leverage new monetization models
around things like In-App purchase and Ads.
So how many of you were at
the Android Market talk earlier today?
So one of the things that's kind of amazing
is that we've now put up a list
of top-grossing applications on Android Market.
Now what's shocking about that
is that out of the top five
top-grossing applications
three of them are solely funded through In-App Payments,
and we've only introduced In-App Payments a month ago.
So this is something that is working.
So again,
if you have something like this
when you-- when a license check fails,
there's a good chance
this is not going to do anything valuable for you.
Okay, your customer is going to get annoyed.
Even worse, if this comes up
when they've legitimately purchased the app,
they're gonna be really upset.
Although actually I-I would find that kind of cool.
But, uh... [laughter]
Galpin: But--but there are ways in which we can approach this,
again, as a marketing tool.
So--so think about this
as we go through this presentation.
But let's talk first about what License Verification Library is.
It is your first defense
against piracy.
And what's cool about it
is that it is not a system that is cookie-cutter system
that every application uses in the same way,
and this is intentional,
because the goal is that someone should not be able
to write a tool
that removes this kind of protection from your app,
where if they write that tool
it's got to be really, really complicated,
because it's going to have to attack
all sorts of different ways you can protect yourself.
And that's really the goal here.
So how does this work?
The application actually determines
how to enforce the policy.
You get to create the dialog that comes up.
You get to create the messaging around it.
You get to use it, again, as a marketing tool if you want to.
In fact, you can simply say,
"Hey, man, I've got kids at home,
and, you know, I make my living off of this."
And you can do whatever you want.
You don't have to be the bad guy
or seem like the bad guy, 'cause, of course, you're not.
You're developers.
Um, and the way this works
is by using public key--
public key cryptog-- public key cryptography.
So we store the private key up in our server,
and your application actually verifies the license,
the signed license response from our server.
Let's talk about how this actually works--
so once again, private key up in our server,
which is actually Android Market,
and public key in your application.
When you want to verify the license, your application
simply sends a "check license request" message
off to the licensing service.
It goes to the server. It comes back down.
And blam, you get a signed response.
Sounds pretty cool.
The nice thing about this
is that it has nothing to do with the platform.
They can be running whatever kind of code they want.
They can be running a routed system.
They can be running another, you know--
whatever they've put on there it doesn't matter,
because your application and the server
are the only two trusted components.
That was obviously done by design.
But there is one problem with this
in that there is a well-known client attack.
And here's what people do.
They use tools to disassemble the code,
and they make simple changes in the code to alter the response
so that instead of returning the licensed or unlicensed,
it alters it.
They reassemble it. They sign it with an alternate signature.
And blam, protection is broken.
So we realized that was going to be an issue.
In fact, when we first released it we suggested
doing a couple of things in order to help strengthen
the defenses of your application.
And since then we've come up with a couple of more ideas,
and I'll share a few of those with you.
So the first and most important thing
is to use an obfuscator,
and it's gonna make it harder
for someone to understand your code when it's disassembled.
The second thing we want to do is to actually modify the LVL.
The LVL is simply an example,
and of course, there's always a problem
whenever you give an example to someone,
is that there is a tremendous, tremendous desire
to want to use it verbatim, no matter how bad it is,
and I've seen this in--in every aspect
of my software engineering career,
and the LVL is no exception.
It it truly just an example
of how to call this service that's with an Android Market,
but it is not in any way designed
to be the beyond and all of piracy protection,
so we modify it.
And we also, and most importantly,
we make the application tamper-resistant.
We want the application to know
if the user has touched it, if the user's re-signed it,
if the user's done something to it
that is going to change its behavior, for a lot of reasons.
I mean, we want people to not be cheating in games
in Android Market either.
So there's a lot of reasons
to make your application tamper-resistant.
And the nice thing about the tamper-resistant stuff
is it doesn't matter. It is not relying on the LVL.
It is entirely independent of what goes on in LVL.
So let's talk about invocation/response handling.
One of the things that the LVL does wrong
is it invokes itself in onCreate,
which is a logical place
if you want to invoke something like this.
After all, your activity's being created right then.
It's very, very obvious.
The problem with that is it's very obvious
to anyone who's trying to hack your code
that that's where you would put it,
and it's always going to happen at the same time,
during start-up, so it's very easy to trap.
So it's much, much better to put in a function,
first of all, that's obfuscated,
that--that isn't called by the framework,
and secondly, doing it in a background thread.
Doing it at some random time makes it a lot harder to trap.
Finally, again,
allowing for a limited amount of game play is kind of cool.
I mean, first of all, it becomes an immediate marketing tool,
and, uh, and secondly, you know,
it--it actually gives you the ability to recover nicely.
Like, if the user actually has to wait for that license check
at the beginning of every single game,
you're inconveniencing all of your legitimate users,
and that's not fun either.
Um, definitely this third one is super, super important,
and we might even see a result of that in this session,
because we're gonna be demoing a couple of license check stuff,
and you'll see, especially in a room like this
where there's not gonna be a lot of Wi-Fi issues probably
or network issues,
it's very possible these checks are gonna fail.
And so you're gonna want to make sure
that the failure you get, um,
it's actually not just "license failed,"
but it's "license failed because the user is unlicensed,"
not failed because the network is down.
'Cause that-- there's nothing worse
than trying to launch a game when you're on a plane,
getting an unlicensed response and then saying,
"Sorry, you're gonna be bored for the next eight hours
because of this."
Again, we don't want to inconvenience
our legitimate users as much as possible.
And then finally, another thing we can do
is rather than just chaining off our code
and going and invoking something like a dialog,
which is very, very easy to spot,
invoke another activity that actually does it for us.
It makes it a lot harder to track how that happened.
Okay, here is the core logic
in the existing LVL,
and there are a lot of problems with this core logic.
Um, one of them--
well, I'll-- I'll go through them.
Uh, first of all, let's go through some updated code.
So first of all this looks a little different.
Now one is that we are not using
simple values like 0 and 1 to mean licensed or not licensed.
We're actually taking those values.
We're performing some sort of transform on them so it's harder
to see in the assembly code what's going on.
The second thing we're doing
is we're actually shoving a bunch of code in between,
and the reason why we're doing this
is that it makes it a lot harder to see,
"All right, well, there's that...
Now what are they doing with that value?"
You've got to actually follow it through the code.
Even better if it's an--
ultimately a different function, or it's handled somewhere else,
as long as it's being stopped somewhere.
So that's a really simple thing you can do.
Again, the idea--make it harder for any simple tools
in order to crack your application.
Tamper resistance--this is actually my favorite part.
Um, so the first thing you can do
and the easiest thing you can do
is to check to make sure your application signature matches--
now the signature is actually the thing
that's on your certificate that is used
to sign the application-- so it does remain consistent
between different builds of your application,
and that can be done just by going to the Package Manager
and calling "get signatures,"
returning in this case the first one.
Pretty simple.
In this case I am actually hashing the signature.
Kind of nice-- you aren't storing a big string
that's obvious in the application.
We're just storing an integer.
That's pretty straightforward.
That way if someone re-signs it we can immediately tell.
Um, we also want to make sure it's not debuggable, you know,
because if it is we probably want to do something different.
It makes it harder for someone to track using the debugger.
So that's easy to do, too.
We can CRC code files and compare.
Now this sounds like it's gonna be really expensive to do--
I mean, you have to go through all of your code files--
but it turns out that all of your--all of your files
are actually CRC'ed for you
because they're all inside of zip packages inside of the APK.
So we can just take advantage of that.
In this case now we have it.
We've now in, you know, four lines of code,
CRC'ed all of our source files,
and we've gotten the value for that,
and so we can check to see
if our Dalvik files have been changed.
So another thing we can do if we want to go farther with this--
and this is kind of nice
because it uses a completely different API--
is we can check to see if our whole certificate matches.
So this is just using the fact that--that actually APK files
are very similar to JAR files, and you can use
these same functions which are part of our framework
in order to actually pull the certificates out.
So one more thing you can do.
Now, again, this is all pretty basic stuff.
Another thing you might want to consider
is actually adding reflection.
Reflection is definitely something you can do
to obfuscate your code.
It can also make your code easier to hack,
so we have to be careful when we use this.
So let's look at our previous example,
which gets the hash of the first signature.
Now we can implement this using reflection
in a couple of different ways.
One of the things that I'm doing here
is I'm actually Base64 encoding
the strings that I'm using for reflection,
again, making it harder to track
what's going on in the actual source code.
The other thing that I'm doing is obviously this is--
there's gonna be no linkage inside of the application
that says we're actually calling something
in the Package Manager.
And this is actually important, because pretty much
any of the tools that people are using to analyze APKs
are watching for calls to the Package Manager.
That's--that's--that's-- they recognize
that people are using these things already.
So this is actually a really good way
of making--making those tools much, much harder to write,
making it much, much harder
for your applications to get compromised.
Another thing we can do is actually add native code.
So if you happen to have a native module,
you can write that same thing that I did--
that I showed before, looking something like this.
Now, okay, admittedly
this is a lot of code,
but that's because this is actually a combination of using
reflection and JNI,
and the first section of it
actually is really the reflective part.
And all we're doing is getting
the IEDs for all our functions and our objects,
and you really only do this once when the application starts.
And the code that actually does the checking itself
looks like that,
so pretty straightforward.
Again, it's very similar.
We're just calling a couple of methods in here.
Of course, obfuscating is important.
We've actually added support for ProGuard
into the latest version of the tools.
But we realized that there was a problem in the LVL
that made it very difficult to obfuscate what was going on.
So anyone who's actually using an obfuscator
should make this change.
So what we were doing is we were actually
binding to the service based upon the class
that was actually inside of the LVL,
which means when the obfuscator went and changed that class name
everything didn't work.
And in fact there's an elaborate work-around
in the ProGuard file
that comes with the current, uh, SDK.
But the good news
is that in fact you can remove that work-around
and change this to something else.
And again, now we've got a string there
that makes it really obvious,
so we should transform that string somehow,
again, use something.
I-I don't necessarily suggest Base64--
That's kind of obvious-- but there are a lot of ways
we can transform that string so it's much, much harder
for when someone's looking for the code
to figure out where we're actually doing the check.
All right, another thing we can do
is actually put the entire check into C/C++ code,
again, taking advantage of the fact
that our application is actually a zip file.
So what we've done here is--okay, sorry.
This is a little different. Um... [laughs]
This is--this is actually CRC'ing classes.
This is the same example we had before.
CRC'ing classes taking advantage of the fact
that it's a zip file, once again using JNI.
But what's kind of cool
is we can actually go a little farther than this,
and we can actually go and use
some publicly available libraries that are out there,
and this on--in this case
we're using MiniZip to do the exact same thing.
And this line of code,
when placed within the right part of the MiniZip library,
will actually, entirely in need of code,
allow you to check the CRC of your main classes file.
And this--this is great because it means
that they're not gonna have anything in Dalvik to look for
when they're trying to figure out
how to hack your application.
They're actually have to go modify the native library.
It's, again, one more step that they're gonna have to take.
It makes it just that much harder
for them to work around all of this.
Finally, if you are going to call native code
within your application,
consider registering your native signatures from your class file
with "javap-s,"
um, using this register native method function.
And we're gonna talk about this
a little bit in the next session we're doing,
which is on "C and C++ Bringing Games to Android,"
but I just want--I thought I'd mention this here
because it's very, very useful.
Because by registering your methods manually
rather than dynamically, it makes the name--
it means you can control what the names are going to be,
and ultimately that makes it just that much harder to track,
'cause the standard names that are giving by JNI
are very, very easy to see.
Anyone can look at your library
and see where those entry points are.
This just hides them a little bit more.
And, of course, we can go further.
Um, I'm not gonna get into these kinds of things.
We can actually store things as encrypted resources.
We can use the class loader.
There's all sorts of crazy stuff you can do in Dalvik,
and I definitely recommend looking at it.
This is kind of fun.
Um, you know, eventually we do have
kind of diminishing returns here.
Um, most of the things that I talked about here
can be implemented in literally just a few hours of work,
and if after you've spent months working on your title,
it makes a lot of sense to take those few hours of work
because it does actually, believe it or not, help.
And we've seen this with several applications on Market
that have taken these kinds of techniques,
and they have improved their ability
to protect against piracy.
But there's something even worse than pirates...
and that is, well, vampires.
And here's what I mean when I say "vampires."
Games and other titles
often have server components,
and sometimes Android games have asset downloads,
'cause they're really big.
But if someone runs your title unauthorized,
they are sucking your bandwidth,
and that costs you money.
So what we can do
is we can actually stop vampires
by making sure our servers actually understand
how this whole system works...
and the way we can do this is fairly straightforward.
So remember I showed you that slide earlier
talking about how we did client side validation.
Well, the server side validation is pretty much the same thing.
Public key is in the market licensing--
sorry, private key is in the market licensing server,
and the public key is actually in our server.
It's no longer even in our application.
And now what happens is we check the license request,
send it off to the server, and it comes back.
And our application,
instead of doing anything with that signed response,
actually sends it up to the server.
And at this point the server is actually responsible
for doing any validation,
and it actually sends, in this case,
a session token back to the application,
which can then be used to download whatever you like.
Sounds pretty cool.
Once again, now it doesn't even matter
if the application itself is compromised.
Ultimately what we're really doing is proxy-ing
a transaction between two servers,
your server and our server.
Now there is one potential problem with this
and that is, of course, replay attacks.
We want to avoid replay attacks.
We want to make sure that someone
can't just capture one of these sessions
and use it to download the files
and embed it back into the application.
So the good news is that we have something called the nonce
in a license validation transaction.
And you've got a couple of options
for how you might want to use that.
Um, you can generate it on your server,
and you can store all the nonce values,
and that allows you to guarantee
that each one of these license validation checks
is only used once,
and you're always going to have to use a fresh one
in order to validate the license on an application.
The other thing you can do is generate it on the client
and have the server store it afterwards.
A little bit more--a little bit harder to deal with
in terms of security,
uh, because you, in theory, could have collisions,
but it's highly unlikely.
So another thing, as I alluded to earlier,
is we can change the monetization model--
and, you know, a lot of this is about games,
but this applies to all applications as well--
so, of course, considering free versions that are upgradeable,
using game mechanics,
you know, gamify actually the game play
so that we can actually drive people into content,
and of course, providing things that extend the game
and make a premium experience.
So let's talk a little bit
about Android Market In-app Billing.
Now this is a great feature.
We announced it and released it just a few months ago,
and we've seen great uptake with it already.
It allows you to purchase virtual goods and consumables.
And again, we allow--we can do
both client-side and server-side validation.
So our managed items are things like your application.
They're things that can only be purchased once.
But the good news is that your application
can actually ask the server to replay these items,
and they're really designed for applications
that don't necessarily have a server component.
And in fact, you can even set it up
so that if someone buys an item
on one instance of an application
you make it show up on another instance
of the application on another device automatically,
but you don't have to do that.
Unmanaged items are SKUs in Market like your application,
but they can be purchased multiple times,
and your application cannot ask for a replay,
so these are harder to secure.
It--it--it--having your own server
is really, really useful in all of these cases
but especially in the case of unmanaged items.
So how does this look?
Well, at a high level,
it actually looks almost exactly the same
as what we did with the license validation library.
We have the private key sitting in the Market server,
and the public key in our application.
And we send a request off.
It signs it with that key.
It comes back, bam, into our billing receiver.
The server version is almost identical.
Once again, at a high level this is what it looks like...
pretty straightforward.
Now one thing I'm doing here,
and I thought I'd point this out,
is I'm adding credentials,
and this might be useful if what we're trying to do
is actually support account information
across multiple devices.
Ultimately what's going to happen
is that this--this transaction
is going to end up getting an ID
that's generated by the server.
But in order to avoid any possibility of replay attacks,
adding a credential is actually useful.
And once again, now that we have our server-side version,
we can do the same thing.
We can deliver new content
as the result of an In-app Billing transaction.
But let's go a little bit deeper here
because In-app Billing is slightly more complicated to use
than license validation for obvious reasons.
So here is our application activity,
and here is Android Market.
And the way this works
is we start off by requesting a purchase.
Now before you do this,
you should make sure that you actually are
on a version of Android Market that supports In-app Billing,
and there's a call to do that.
I'm not gonna go through that.
Then it ends up bundling a response code
that includes a purchase intent,
and we are then going to execute.
We're gonna invoke that with a StartIntentSender
if we're on Android 2.0 or above,
and that causes the checkout UI to get displayed
on top of our application,
and it actually comes up as non-full screen activity,
which means that our application
then goes into onPause() state.
Now for those of you who are writing games,
if you, at this point, go and dump all of your textures,
you're going to--or you're using the standard GLSurfaceView
that dumps all of your textures, you're gonna find out
that it's gonna take a couple seconds potentially
for this to come back when you reload everything.
So you might want to take a look at this case
and optimize around it,
so in fact we don't necessarily dump until onStop().
Then the user's gonna actually say they buy something,
and we get an activity onResume()
followed by a broadcast result code
saying what happened.
So then we--then we, of course, say, "Well, what did they buy?"
We get the information,
and it comes back in a broadcast.
Now the key thing about these operations
is that the first section here,
the request purchase and that bundle,
are synchronous.
After that, these are entirely asynchronous operations.
So it means that you have to think about it
when you're writing your application.
You have to make sure
that there's something that the user knows,
that there's something still going on in the background.
It may take a while.
We have fraud prevention and all sorts of stuff on the back end
that we try to do to make sure
that the system is working to its best,
but that can take some time.
So there is a delay that will happen here.
Finally, at the end of this,
we get a "purchase state changed"
that lets us know that
the purchase actually went through or didn't go through.
And then we say to the server, "Yes, I got that message,"
which is important,
because if we don't actually confirm the notification
the server's gonna try to keep delivering that notification
to us again and again and again until we confirm it,
which is very, very useful, because your application
could get killed in the middle of this,
and you want to make sure that when your application
is up and running, it actually gets a notification,
confirms it, so you actually purchase the item,
give the user what they-- what they bought.
And then finally it lets you know
that it received your confirmation.
So that's how you do it without a server component.
In order to add a server component to this
it's pretty straightforward.
We're gonna use the technique in which the server
actually generates the nonce.
So we're gonna start off with sending a request to our server
to get that nonce and getting that nonce back.
And then when we actually go to confirm the notification,
what we're actually going to do
is perform the server billing side authentication
on our server,
send it--send it the credentials
that it's gotten back from Market,
and then finally return the validated
that we've routed to the billing response.
Now in our particular example,
all that we've done is actually taken a session ID
that we generated earlier and validated it
and--and Trevor's gonna be demonstrating that
in just a moment.
So, Trevor, if you could come up, actually. [laughs]
Johns: Okay, so if we can switch over to our project here...
Galpin: Yes.
Johns: Which I think is number three.
Galpin: Sounds good.
Johns: Ah, there we go.
All right, so this is a small little demo app
that me and Dan have been working on,
um, to go and demonstrate all this.
We'll be releasing the code, um, sometime after the--
after Google I/O is-- after Google I/O is over
for all of you to download and take a look at.
But basically it just goes through
exactly what we just talked about.
So I have my, uh, nice little downloader app here.
You can tell that the UI's very, very awesome, right?
[laughs]
Um, and we implemented both techniques you can use here,
either, um, checking a license server certificate
or through In-App Billing.
So we're gonna show you In-App Billing here.
And so when I push that,
two things are happening behind the scenes here,
assuming Wi-Fi works.
First off we're going to go and get that nonce,
and then we go, and as soon as we get that,
we make our In-App Billing request.
So let's go ahead and buy this
with my nice fake credit card here.
All right.
That comes back.
Um, you see a slight delay there while we wait for Market
to go and confirm everything for us,
and then we get a "Download Content" button.
And so when we push "Download Content" here,
two more things are gonna happen.
First, we're gonna go and take all of this time data
that Market sent us and send it back to the server.
The server's gonna go and upgrade our session token,
and then we're gonna go
and start downloading our files...
if Wi-Fi works. [laughs]
So, um, ah, and there you go.
So I could go into the Market-- uh, Publisher Console
and go--instead of--instead of a-a license response--
or a purchase response,
we can go and set it to, um, send us--Excuse me.
Since this is In-App Billing
I can go and change the test SKU and say that we're--
that the purchase didn't go through,
but I'm not gonna do that, 'cause, quite frankly,
it's not that interesting.
Nothing happens. Everything stops.
Which is exactly what you want, right.
And so when this finishes downloading,
which, um, probably will take another minute here,
so I'm not gonna bore you all, we get a nice little video file.
You can click "play," and you'll get a nice app
of all the Android app--all the Android--er, activations.
So, um... Galpin: So this is an example--
yeah, I should probably continue on.
Um, so this--we're not gonna switch to the slides.
I do want to actually show that.
But what's kind of cool about this
is this is actually a sample that we wrote
that takes the original source code that was given in both
the license validation library and the In-App Billing library
and actually ports it to standard Java SE,
and it's running on-- under App Engine.
Johns: Correct. Galpin: And, uh,
and we're actually playing... Johns: Yay.
Galpin: One of my favorite videos.
Um, actually all the time. Johns: So like Dan said,
the important thing to note here is this is the same source code
you have as part of the Android SDK.
And since it's Java code,
and App Engine also supports Java,
we can pretty easily just go and copy that over,
and it actually doesn't take too much work to get it working.
Galpin: That's right.
Even Trevor and I can do it,
which means all of you can do it.
Johns: Yep. Right. Let's go back to the slides.
Maybe. There we go. Galpin: All right. There we are.
Okay, so let's talk just a little bit
about App Engine,
and App Engine has been really good to us,
because we needed a place where we could host that Java code
and do that validation and also, in this case,
host the buying that we're actually downloading.
So, of course, it allows you to run your Java code
on our infrastructure.
In this case we're using it to validate license responses,
secure transactions,
and serve files directly from the Blobstore.
And--and what we're actually doing is there's actually
three different programs in action here.
There's actually an App Engine application,
which is handling almost everything.
There's actually a small python script that we wrote
that actually does bulk uploading into App Engine
and stores things in the Blobstore.
And then, of course, there's the Android side module,
which we just demonstrated.
And again, this is useful as an example.
But remember, this is just standard code.
It can be run on any Java-capable server.
So how do we create an App Engine project?
So I'm gonna go through this very, very quickly,
but it is very, very easy
specially if you like using Eclipse,
or if you just have Eclipse.
You can just install the plug-in.
You can then literally go through this wizard,
which will create the App Engine project for you,
and it creates a little servlet that you can fill in.
And then you can literally launch that servlet
by going and clicking "Deploy to App Engine."
It really is pretty much that simple.
And we give you a bunch of tools to manage it as well.
You can look at bandwidth.
You can see who's connecting to it.
It's kind of cool. You can also get log-in information.
But let's look at what the code actually was like on App Engine.
So now admittedly this is not--
I'm not gonna show the entire ported code,
'cause it would take a long time.
It would bore you even more.
So what I am gonna do is show you the module
that actually handles the request for data
and does the validation.
So all this--all this is doing here
is actually gonna generate a session.
And what we're doing here is we're actually getting
the signature from the device,
and we're passing it
through that same licensed validator class
that is part of the LVL.
We're calling verified just like we would do on the device,
and then we're returning that value
as part of a new session token which is now validated.
Now again, you know, this is just an example
of how one can build this kind of server,
but it's pretty straightforward.
There's a very small amount of code
that needs to be actually written.
So while I have you all here,
let me talk a little bit about Cloud services in general.
So your application actually can take advantage
of Cloud to Device Messaging, which is, of course,
basically what we're using for the background
for Google Talk and for GMAIL to send messages.
Also, the backup service.
And then, of course, in that-- in that other pile
we have Android Market, licensing and billing,
which I've talked about here.
So Cloud to Device Messaging--
we announced it last year at Google I/O.
It's pretty cool.
It launches your app if it's not running.
It leverages our network connection,
and it queues and delivers messages.
And it's pretty straightforward to set up,
and I'll go through a real basic flow here.
And the reason why I'm bringing these things in
as part of this application
is these are all part of bunch of Cloud services
you can take advantage of in your application.
And I think it's important, especially now that we're seeing
such an enormous number-- percentage of devices
that are running Froyo,
that people, for example, start to take advantage of C2DM.
We're at over 65% of devices now that are running Froyo.
So basically we start with the registration flow.
It's pretty simple.
Your application needs to register itself with the server,
and your application has to forward that idea across.
Then on the back end side
your server actually has to create
and store a session with Cloud to Device Messaging
and finally return the response.
After that point, you can send messages to the service,
and it's going to send intents to your application,
Pretty straightforward.
Application data backup is kind of interesting as well.
Um, one of the things that--
that I found is really frustrating
is that I move around between Android devices a lot.
I don't know how many of you do that,
but I find I do it more than most probably.
And it's really frustrating if I'm playing a title
or playing a game, or if I even have settings,
and they don't end up
getting transferred automatically between devices.
And of course, we provide that capability
with application data backup,
and I want more applications to use it.
It also can be used for a couple of cool ideas.
Like if you want to be able to track things
going across devices,
you can actually have that same session carried across devices
with application data backup.
And this flows pretty straightforward as well.
You basically tell the backup manager
when you have data that has changed.
It then gives you an onBackup() request,
and it backs things up to the Cloud.
Now obviously, um,
uh, you know, if you look at this,
this is actually part of the framework.
This is actually not tied to Android Market,
so you're relying on
whatever Cloud backup infrastructure is on the device.
Restoring is pretty much straightforward as well.
If the application is installed,
if data is backed up,
it will send you an onRestore().
So it's pretty straightforward,
and it allows you to do a lot of things,
and it can also help you track what's going on
with usage across users.
So one more thing--
if you like the Androids in this presentation,
please consider Androidifying yourself.
It's really fun.
And it saved me a lot of time making artwork.
[laughter]
Galpin: So, uh, now we're gonna open up the floor for questions.
Now please use the microphones
so that people outside of this room can hear you
or maybe even so that people inside of this room can hear,
and Trevor and I can both take your questions.
Thank you. [applause]
man: So if you're doing something--
like you mentioned you're downloading this large movie.
You don't want them to download the movie
and then just send it to all their friends.
Are you doing that
by virtue of putting that in the application store?
Galpin: Well, you know, you've got a couple of options here.
I mean, I think that-- I think in this particular case
we want to stop them from using bandwidth on our server.
Our goal was not to actually try to protect the content.
That's a secondary thing.
Now, of course, you can take that content, whatever it is.
You can encrypt it however you like.
You can get a lot of per device data there,
and you can do that on your back end.
But that's kind of a secondary problem
versus the problem of just trying
to prevent someone from leeching off your bandwidth, which is
what we were, in this case, particularly talking about.
man: Okay. Um, and if you don't have your own server,
the Android Market doesn't have any mechanism
for storing binaries.
You need to kind of create your own server for that.
Galpin: Well, as far as what's tied in In-App Billing,
that's correct.
At the moment we do not have anything like that.
But again we do have things like App Engine.
App Engine has a certain amount of free quota,
and it's, you know-- so there are ways in which,
depending on how much data you have to store,
you can still find facilities out there on the Web,
whether it's through us or through someone else.
man: Okay. Thank you. Galpin: Sure.
Coryat: Yes, my name's John Coryat.
I have a free app called Radar Now.
Um, I have, like, uh,
about a million, um, active users,
and implementing, like, license checks and stuff like that,
I'm not sure if that's good for a free app.
I'd like to implement In-App Billing,
but, you know, that's adding another layer.
What's your feeling on that? Galpin: Well, so license--
I should have made this clear at the start.
So license validation is something
that only applies to a paid application.
Coryat: Okay. Galpin: And, uh,
and as far as In-App Billing is concerned, um, you know,
I think that, uh, if it fits the business model,
you know, I-I think it can make sense.
You know, obviously you have to have something
to drive someone to it. If you do use In-App Billing,
and you're doing an app that's not server-driven,
I'd definitely recommend using a lot of these same checks
we were talking about in terms of integrity,
because, again, that now becomes a surface area
for someone to attack, so, uh-- but for a free application
it's typically not something that's required.
Coryat: Yeah, so what I have in mind is adding features
that have been requested over the last two years
by users begging for new stuff and, uh...
Galpin: Mm-hmm.
Coryat: And the In-App Billing thing seems perfect.
I want to implement in a subscription roll
on my own server. Galpin: Mm-hmm.
Coryat: That's no issue, right?
Galpin: So the only issue with In-App Billing and subscriptions
is there's currently no support for subscriptions.
in our In-App Billing directly,
but you can use it as an unmanaged item,
and you can manage those transactions yourself.
So you can just notify the user
that their subscription's running out.
They have to do another purchase.
Coryat: Very good. Thanks very much.
Galpin: Sure.
man: I would like to ask a question.
Once you have pirated apps out there, um,
and so then you can implement the LVL and stuff,
but other than coming out with new updates with great features,
is there anything else that you can do
with things that are out there in the wild?
Galpin: Um, if you don't have a server component, it's tough.
I mean, you know, obviously--
obviously, um, my general-- my general feeling
is that it's useful for every application
to have some kind of server component if possible,
even if that's just for analytics.
I think it's important for applications to track--
for developers to know who's using their applications,
where they are, what kind of install rate they're getting,
even beyond what they get from Market, which is pretty good.
But that--so my feeling is, yeah, it's hard.
I mean, once it's--once it's truly out there,
there's not a lot you can do, so...
Stone: Hi, my name is Bo Stone.
I do DroidIn for LinkedIn.
It's a first-ever LinkedIn app. Galpin: Mm-hmm.
Stone: Um, and here's the question.
Uh, I have a pro version of the app,
and all it really does is removes the ads,
you know, Google ad, um, from--from the application,
so I would like going forward
to make it available as, um,
basically in-Market purchase,
In-App purchase. Galpin: Mm-hmm.
Stone: But what's really stopping me
is that, uh, what do I do with all the custom--
all my happy customers that already have it?
So if I remove that code that, you know, that I already have
for verifying the license,
what are they gonna do with my future releases?
And so if you don't have that, I mean,
I treat it as a request.
I just need a mechanism of taking that existing license
and maybe giving my customers a voucher
that they can basically then go into a Market site
and purchase--
basically use it to--to convert that license
into In-App license. Galpin: Right.
I mean, I think, so I mean--
so the only way to do that right now with the system
is--is for it to be an unmanaged transaction
for you to store that kind of information on your server.
'Cause that gives you
all the flexibility to control how you use it.
So you know, put up a-- if you put up a little server,
and you tack on there, it's still not a perfect solution,
and I'd like to support that, honestly,
but, uh, you know, right now the only way you can do that
is through an unmanaged transaction.
Stone: All right, thank you. Galpin: Sure.
man: Um, yes, hello.
In terms of, like--
this was mainly for, let's say, paid apps
or In-App transaction.
But for instance, if I want to just save some information
and want to obfuscate it, let's say,
like an API token... Galpin: Right.
man: and sometimes a secret as well,
is there any best practice?
I mean, would you recommend a way to ensure
we can obfuscate some data
that's either specific to a user,
like, uh, some kind of passwords,
something of that sort... Galpin: Mm-hmm.
man: or a token, in a way that makes it difficult
to just achieve easily,
and where would-- where would you place it?
Galpin: Well, I mean, ultimately--
so, I mean, ultimately I guess there's kind of two things.
If you're trying to protect the user's data
from other applications,
the platform does a pretty good job of doing that already,
um, as long as you store data in private locations,
you know, and that's-- and that's one of the places
in which the platform really tries to secure data.
Um, and of course, obfuscating things on top of that is good,
uh, uh, because, of course,
the platform could be compromised.
There's no such thing as a perfect system.
But, um, but in general that's--that's the--
the platform tries very, very hard
to make sure that there is a sandbox
that applications can't get out of to make that happen.
Um, as far as best practices in general for obfuscating,
I mean, I think that, uh,
you know, some of the things we talked about here
are--are not exactly relevant to actually obfuscating data.
But if you look inside of the LVL,
there's actually an obfuscated preferences module
that we actually give you a source code,
and that's probably a good place to start.
And it includes--it includes
a pretty straightforward implementation of that,
and you can certainly grab that code and use it.
It's part of the freely available library.
man: Okay, and just as a continuation of that,
would you always execute some kind of--
I suppose you have to--
but obfuscation and all this kind of processing power
just every time you need to access it?
So for instance if you have like a [speaking indistinctly]
where you want to know if the user is logged in,
do you each time have to execute,
let's say, this entire process of running a thread
and you know... Galpin: I mean--
I mean, I think that it really depends on--on
whether it's gonna adversely affect
the performance of your app.
If it's not, then I see no reason
why not to execute it all the time.
If it does, then obviously you're gonna want to make
a compromise between some level of security
and some level of performance.
I think it's really on an app-by-app basis.
man: Okay, thank you.
man: Hi. Galpin: Oh, yeah.
man: My question is on the free apps.
You know, free apps... [speaking indistinctly]
the license validation check, right?
But I still want to do the vampire attack.
You know, some unknown people are taking my free app
and start using my service site resources.
So how do I go about protecting that kind of, you know,
free apps but at the same time vampire attacks?
Galpin: It's an interesting problem.
I mean, I guess-- I guess the question is,
you know, in general with the free app
the goal is to have as many users as possible,
so are people misusing your app in some way,
or is it--or... man: Yeah.
For example, take the code and decompile and, you know,
modify certain things... Galpin: Right.
man: and make it work on some other device,
which we really don't want to work on certain device.
Galpin: I see. I see.
Yeah, I mean, you know, in that case,
LVL isn't really gonna help you
because ultimately the thing to do is focus on integrity checks
and try to make sure that the code is--is
as functionless as possible in those cases,
and you know, make sure that--
you know, if someone's touched your code,
a lot of those things will really make it very challenging
for them to--to get your application to work.
And you know, hopefully they'll give up,
but if they don't, you know, that's--that's--
at least hopefully you've prevented--you've created
a window of opportunity for your application.
Now if you're using--
if you're talking about using server-side resources,
a lot of the things you can do
are actually take things like-- encrypt pieces.
One of the things that's very successful, actually,
is taking, um, pieces of your code that are well-known
and using them as keys that you send up to your encrypt--
up to your server.
So do things like grab the CRC of this
and don't necessarily use it for an integrity check,
but actually use it as a key
that the server ends up using to send content.
So that's another method.
You can actually directly incorporate integrity checks
into helping prevent misuse of your application.
Johns: Yeah, and it's also worth noting, I mean,
what you're trying to do ultimately
when you're trying to do an application integrity check
is make sure nobody's tampered with the system.
And to do that, you really need something like a DPM,
which unfortunately Android doesn't have support for.
Um, who knows.
At some point in the future we may or may not get that,
but really that's the missing piece
for what you're trying to do there.
Galpin: But the key thing, I think, is, you know, again,
you can take advantage of values that come from integrity checks,
things like the CRC, things like your application signature,
things that are very difficult to tamper with and use those
as--and send them directly to your application
and use those to actually validate what's going on.
Now again, all this stuff can be spoofed.
It's not a perfect system,
but you can make it pretty challenging
for someone to figure out what's going on.
man: Continuation on that,
you said that application can proxy the, you know,
encrypted data coming from the Android Market
and then send it to our server in the back end.
Galpin: Mm-hmm.
man: But what server has to do at that point, you know,
how do they validate the response?
Galpin: So ultimately it's what I was talking about before.
The Android Market signs everything with a, um,
with a private key,
and then so what you do is you put the public key
that's associated with that private key--
and we give that to you on Android Market.
You put that on your server,
and you actually use that to validate the signature
that comes back in from Android Market.
So that's how it creates a relatively secure channel
between the Market and your application,
even though the Market server isn't directly talking
to your server. man: Oh, thank you.
Johns: Yeah, and a take a look in the In-App Billing code.
There's a security Java file
that shows you exactly how to validate that response,
and the source code we'll be releasing
will show you how to do that. Galpin: Yeah, exactly.
man: In the sample project that you created,
did you actually take the time
to decompile your own application and try to hack it?
And in that case, which methods
did you find were easier to circumvent than others?
Galpin: So-- Johns: This one in particular--
um, well, to answer the first part of your question, yes.
man: Okay. John: But in this case
since we're doing service side validation,
there's actually no attack window on the device,
um, 'cause really what you're doing
is validating a signed piece of data
that's coming from the Market server.
So assuming that you can't tamper with
the Market server code, which hopefully you can't,
um, and assuming nobody can tamper with your server,
um, you know, all the actual validation
is being done on those ends, and the device itself
is just acting as a conduit for the two to talk to each other.
man: That applies to your In-App purchasing example.
Johns: Right.
Galpin: And the LVL example as well.
What's more interesting
is when you get into the anti-tampering examples.
And so there actually are tools out there
that you can actually run, uh, and, uh,
there are--there are some Web sites
that have created some fairly sophisticated tools
that try to break this kind of protection.
So that'd be my first-- my first effort on that.
And, yeah, I actually designed some of these examples
based upon the results of that tool.
Now, of course, the tool is gonna get updated,
so don't use my examples verbatim.
Uh, but, uh, but definitely that's a good place to start.
The last thing you want
is for you to put a lot of work into something
and to have it immediately get--get compromised.
man: I also have a follow-up question.
Um, what are your thoughts on third-party libraries,
such as Urban Airship,
and the services they provide versus how basically
it's essentially copy and paste for every application?
Galpin: Uh... man: Are you familiar?
Galpin: I'm not.
I don't have enough familiarity with what they're doing.
man: Basically they handle the server-side validation,
and you drop it into your application,
and they provide the transport mechanism
for the content to your device. Galpin: Mm-hmm.
I've heard--I've seen some things like that.
Yeah, I don't really have an opinion on it.
If they work, that's great.
It's not--again, we're just trying to show you
how to use the APIs to do it. man: Right.
Galpin: But if they're doing it for you, that's awesome.
man: And what is the best way to use In-App Payments
for opening
some extra premium features of the application?
Because in this case you will--
you should have all this code
also inside the application,
and an attacker can use all those techniques to open it.
Galpin: So my--my general best practice on that
is to try to have resources that are not in your application
that have to be pulled in from a server.
And if that--and even better if they can be encrypted
with some device-specific information
that makes it a lot harder for someone to break it and use it,
especially if that decryption is being done,
like, inside of native code, or it's being--
you know, for a lot of game titles,
that's actually very, very easy.
That's how they're already accessing those assets.
So that would be one way
if you want to actually put-- put a little bit more, um, uh,
to make it a little bit harder, a little bit more obfuscated.
So I-I like that method.
Um, there are plenty of other methods, too.
I mean, um, if you look at the latest versions of Unity.
Um, they--they actually do a bunch of things
to try to help people out in this exact same way,
uh, in order to help them encrypt resources
and unlock things in the application.
But I think the best practice
is to actually download something else additional
to the application.
man: Even DEX files to the memory?
Galpin: Um, the problem with DEX--DEX files are interesting.
The problem with DEX files is that you can't, um,
you can't actually encrypt them because they have to--
and they have to be loaded in the internal file system.
You can't actually load them from memory
with our class loader.
So, um, yes, that's not-- that's not a bad idea
if it's a small class that does something integral,
but it--it is--it doesn't necessarily provide you
that much protection,
and it is a lot of work to set up.
And it also is something that, you know,
in general downloading code
is sort of a questionable practice
even though it does, um, it does--
even though the--the actual system will prevent it
from getting to any resources that your application
hasn't already-- hasn't already asked for.
It does provide-- it does mean that your app
is ultimately responsible for
a potential additional vector for compromising the system.
So as a general rule, you know, yes, um,
it's one way of doing things,
but it does mean that your application could potentially
be used by something else that's naughty
if it can figure out how you're dealing with that DEX file.
man: Okay, thanks.
man: Hi, Dan.
I--why not close the loop and have the Market server
communicate with your server?
Johns: [laughs] Galpin: It's--it's--
it's something that I think would be--
would be an excellent addition to the API.
I don't think cryptographically it's required.
Uh, but I think that it would make--
it would make life a little bit easier
for some--for some applications, and it's something
that certainly we've talked to the Market team about.
Johns: Yeah, so just to follow up on that and to be clear--
from a security perspective,
the way we're doing it
versus providing an additional API on the market server
that your app could talk to,
they're essentially equivalent.
Um, the downside is having an additional API
actually adds one more round trip worth
of latency to your-- to your check.
Um, but again, there are some--some specific cases
where it might make life easier on developers,
so we--we definitely have a feature request open for that.
man: All right, thanks.
Galpin: All right, well,
if that's it for the questions,
the next session here is going to be on, uh,
bringing your games to Android with C and C++,
and myself and Ian Lewis are gonna present that.
And let us know how we're doing.
I had a speaker meter, uh, URL up there.
And so please, uh, do check in.
We do actually listen to your feedback.
And if you thought this was a giant waste of time,
let us know,
and if you thought it was interesting, let us know.
And we'll be back next
with "Bringing Games to Android with C and C++."
Thank you. [applause]