Certificate Pinning - The MOST Important Security Measure for Network Traffic In Your App — Transcript
Full transcript
- 0:00In this video, we're going to take a
- 0:01look at certificate pinning on Android,
- 0:03which is a very important concept to
- 0:05know about when you're working on
- 0:06security critical apps that involve some
- 0:08form of network traffic like a banking
- 0:10app or something like health related
- 0:13apps with users health data that has
- 0:15been somehow exchanged over the network.
- 0:17But first of all, let's understand what
- 0:18a certificate is really for in the first
- 0:20place. You've probably heard this before
- 0:22that when wanting to communicate with a
- 0:25server via HTTPS, that is on the one
- 0:27hand encrypted by default. That is what
- 0:29the S stands for. So, hypertext transfer
- 0:32protocol secure and that in order to
- 0:34enable HTTPS on your server, you need a
- 0:38signed certificate. How do you actually
- 0:40know there is not any sort of attacker
- 0:42in the middle between your app and your
- 0:44server? Because if the attacker actually
- 0:46kind of owns this communication channel,
- 0:48they could of course kind of also fake a
- 0:50response even if that response is
- 0:51encrypted, feed that encrypted response
- 0:54back to your app, which your app wrongly
- 0:57interprets as the real response from the
- 0:58server. And in order to know that a
- 1:01server is trustworthy, it has to have a
- 1:04certificate that is signed by a
- 1:05so-called CA. So a certificate
- 1:08authority. So there are in the end a
- 1:10bunch of such certificate authorities
- 1:12that the general public considers
- 1:14trustworthy which is in the end
- 1:16responsible of signing such
- 1:18certificates. So examples for such
- 1:20certificate authorities are Google or
- 1:22Amazon. So where you would say if Google
- 1:24or Amazon actually signs a certificate
- 1:26and we can actually see that it was
- 1:27signed by one of these then that should
- 1:29be trustworthy. So what now happens when
- 1:31your Android app is making a normal
- 1:32HTTPS request to a server that owns a
- 1:36certificate and exposes a certificate
- 1:38that was signed by such a certificate
- 1:40authority. What happens is when your app
- 1:43then gets the response, it has a
- 1:44predefined OS level list of these
- 1:48certificate authorities. So there are a
- 1:50bit over a hundred of such authorities
- 1:51that are predefined and baked into the
- 1:53OS. Technically, you can also define
- 1:56your own of such authorities and allow
- 1:58these. But there's definitely a
- 2:00predefined list that when your app then
- 2:03receives the response, we'll simply go
- 2:04over and see, okay, is the signature of
- 2:07this response that we got from this
- 2:09network call actually matching any of
- 2:11these certificate authorities that have
- 2:13been predefined. If it matches, then
- 2:15your app will simply accept the traffic
- 2:17because a trustworthy authority has
- 2:20signed the certificate. So this means
- 2:22it's not that easy for an attacker to
- 2:23actually just fake being Amazon or fake
- 2:26being Google because they don't have
- 2:27that signature these companies have. But
- 2:30if it doesn't match and the attacker
- 2:32maybe just try to generate their own
- 2:34certificate which will then however have
- 2:36a different signature then that
- 2:38signature won't match against any of
- 2:40these predefined certificate authorities
- 2:42on your Android device and that response
- 2:45will in that case be declined. so much
- 2:47about the theory of how these
- 2:49certificates work, but we're not yet at
- 2:51certificate pinning because in the end,
- 2:53the weakest link here breaks the chain.
- 2:55This connection that you've seen here on
- 2:57the previous slide is in in the end only
- 2:59as trustworthy as the certificate
- 3:01authority is. Or in other words, it's
- 3:04only as trustworthy as the kind of
- 3:06weakest link. So the weakest certificate
- 3:08authority here in this whole list of
- 3:10predefined authorities is what can now
- 3:12happen is that such a certificate
- 3:14authority is maybe compromised in some
- 3:16way. It could happen that a malicious
- 3:19certificate is actually issued. So an
- 3:21attacker gets some chance to actually
- 3:22generate a real certificate for your
- 3:25domain by I don't know getting access to
- 3:27your server or so. Or it could simply
- 3:29happen that a malicious certificate
- 3:31authority is simply sitting on your
- 3:32device. As I mentioned, this list can be
- 3:34extended and if there's some kind of a
- 3:37malicious software on the Android device
- 3:39that simply extends this list of
- 3:41predefined certificate authorities and
- 3:43it now says, okay, we have all these
- 3:46trustworthy certificate authorities,
- 3:48Amazon, Google, etc. But now let's also
- 3:50have this additional one here that is
- 3:53technically from me. So the attacker
- 3:55does as if they are a certificate
- 3:57authority by just adding this to this
- 3:58predefined list. This would also be a
- 4:01valid scenario here. So in these cases,
- 4:03that's actually a problem because in any
- 4:05of these three cases, it could
- 4:06technically happen that with this
- 4:08so-called man-in-the-middle attack that
- 4:09an attacker is kind of intercepting your
- 4:12network traffic and I don't know is
- 4:14maybe listening to your login data, you
- 4:17send that and while they can't instantly
- 4:19read what you send because it's
- 4:21encrypted, they could decide about the
- 4:23response. So they could do something
- 4:24like just send you a generic error
- 4:28message here that they say, "Okay, that
- 4:30password wasn't valid." and they kind of
- 4:31redirect you to a different website that
- 4:33looks identical or so. So you just
- 4:35re-enter the password and then with the
- 4:37next request they have it. Something
- 4:39like that is definitely then possible if
- 4:41an attacker then kind of yeah is in the
- 4:43same network for example in the public
- 4:45Wi-Fi. And this of course something we
- 4:47want to prevent with security critical
- 4:49apps and for exactly that certificate
- 4:52pinning exists. Certificate pinning in
- 4:54the end really means that in our Android
- 4:57app we embed a list of hashes of servers
- 5:02public keys that we explicitly trust. So
- 5:05in the end of course all these
- 5:07certificates are lying on some kind of
- 5:09servers that our app connects to that
- 5:10our app needs to make network calls to
- 5:12and a certificate consists of multiple
- 5:14different parts but part of that are for
- 5:16example a public and a private key. The
- 5:17private key is what the server uses,
- 5:19what is definitely a secret, what's used
- 5:21to encrypt the thre the traffic back.
- 5:23And the public key here is really just
- 5:24used to verify a signature. So on the
- 5:27one hand, we have this list of such
- 5:29hashed public keys sitting inside of our
- 5:32Android app that is really embedded into
- 5:33our APK. And on the other hand, there is
- 5:36this one public key here that is sitting
- 5:39on the server. And it's actually one
- 5:41such public key per domain or subdomain.
- 5:44And this public key is simply part of
- 5:46this overall certificate which however
- 5:47comes with more such entries. And when
- 5:50our app now gets a response from a
- 5:52certain server. What it can now do of
- 5:54course is it can match this public key
- 5:56from the server against the undefined
- 5:59list of public keys. So we could say hey
- 6:03here this is a list of public keys of
- 6:06servers or of certificates that we
- 6:08actually trust and only if this public
- 6:11key that we get back from the
- 6:12certificate from the server matches any
- 6:15of these then we trust that response and
- 6:17this is then what we call it matches a
- 6:19pin. So we really pin these public keys.
- 6:22And the problem this really solves is
- 6:23even if an attacker gains access and
- 6:25compromises the certificate authority.
- 6:27So is in the position to actually create
- 6:30new trustworthy certificates for your
- 6:33domain. Those will still be other
- 6:35certificates that won't be the exact
- 6:37same certificate as the one sitting on
- 6:39your server. And if you now say, okay, I
- 6:41know the one that is sitting on my
- 6:43server, you can actually kind of
- 6:44hardcode exactly that certificate in
- 6:47your Android app and you only trust that
- 6:49exact instance of a certificate that is
- 6:52sitting on your server. And that is
- 6:53typically working via the public key,
- 6:55not by hashing the entire certificate,
- 6:57that would be a big mistake because if
- 6:59you would hash the entire certificate,
- 7:01the certificate itself would change when
- 7:03it's being renewed. So that's something
- 7:06that is a very standard practice and
- 7:07it's happening typically every 90 days
- 7:09with these certificates that is that
- 7:10they are simply renewed and regenerated
- 7:13but that would then also break your app
- 7:17because your app is still installed on
- 7:19users devices but if the certificate is
- 7:21changed and the hash therefore has
- 7:23changed then your Android app will break
- 7:25because it doesn't match anymore after
- 7:27it has changed. However, what is
- 7:29definitely possible is to renew a
- 7:31certificate without actually touching
- 7:33the public and private key here. And
- 7:35this is a very important setting for you
- 7:36to make here because otherwise you can
- 7:38really lock out your users here. But if
- 7:41your server is actually configured in a
- 7:43way that this keeper won't change when
- 7:46the certificate renews, then this will
- 7:48obviously also survive renewals. On
- 7:50Android, there are two different ways to
- 7:51do that. On the one hand, via the
- 7:53manifest. That's something I will also
- 7:54really show you in a moment practically.
- 7:56So you really just define a so-called
- 7:58network security config or alternatively
- 8:01you can directly configure this in your
- 8:03network client of choice something like
- 8:05okay HTTP or KO here in this case you're
- 8:07really dynamically define these
- 8:09certificates in your code but the
- 8:11easiest approach is usually just
- 8:12defining the network security config
- 8:14when is this actually justified well not
- 8:17generally because as I mentioned um
- 8:19there is a real risk here if you're
- 8:20doing this wrong you can really lock out
- 8:23your users but for any apps that are
- 8:25really like uh security critical like
- 8:28banking app, fintech, password managers,
- 8:31apps dealing with health data or any
- 8:33super sensitive data that is also shared
- 8:35over the network. Here it really makes
- 8:37sense to think about certificate pinning
- 8:39and really implementing this correctly.
- 8:41Where it's usually not making sense is
- 8:43any typical like consumer apps for
- 8:46example a calorie tracker or some kind
- 8:48of game. So this is really something for
- 8:51apps where you say I really need the
- 8:53highest level of security and I can't
- 8:55tolerate anything below that. But if you
- 8:58have an app where there is no real
- 9:00strong external interest from someone
- 9:02from a positive attacker to get
- 9:04something from this app then you also
- 9:06don't need to think about certificate
- 9:07pinning and it's rather just overkill.
- 9:09So I'm now here in Android Studio and I
- 9:11want to now show you how that really
- 9:12works in practice by having a real app
- 9:15where we will now implement this. And
- 9:17this is really just a a little prepared
- 9:19app here that is making a network call
- 9:22each here for these two button clicks.
- 9:24On the one end, we're making a get
- 9:25request to PL coding to my website. And
- 9:27[clears throat] here we have a get
- 9:28request to Google. And right now, no
- 9:31certificate pinning is implemented at
- 9:32all. So that means if we click this
- 9:34button, it will in this case simply
- 9:36print the response. You can see making
- 9:38the request here. In my case, my website
- 9:40redirects you to the www variant. And
- 9:44then here after making the request over
- 9:47there, this is kind of the raw HTML that
- 9:50my my homepage responded with. So that
- 9:54call is definitely going through here as
- 9:55we can see in lockat. And if we make the
- 9:57request to Google, then we can also see
- 9:59yeah similar thing is happening here.
- 10:01And then here's the entire HTML from
- 10:03Google in this case. But now let's say
- 10:06we h have an app where this network
- 10:08traffic to PL coding must really be
- 10:11secure and we also maybe don't want to
- 10:13allow the network traffic to Google at
- 10:14all. So what we want to do is we want to
- 10:17go inside our
- 10:20resources package inside XML and this is
- 10:24the place where we need to define a
- 10:25network security config. So that's
- 10:27really nothing else than just a normal
- 10:29plain XML file. So XML resource file in
- 10:32this case we want to create this. We'll
- 10:34call it network security config
- 10:39and the root element here would be
- 10:41exactly that network but here with
- 10:43dashes network security config and then
- 10:47we can create this. The autocomplete is
- 10:49usually broken here but that doesn't
- 10:52mean that it won't work. And the first
- 10:53thing we want to do is want to define a
- 10:55base config. The base config in the end
- 10:57defines well the config for any domains
- 11:00that we don't explicitly define
- 11:02something for. So in this network
- 11:03security config we now have a fine
- 11:05grained configuration after all where we
- 11:08can define per domain technically per
- 11:10subdomain
- 11:12whether we want to pin some certificates
- 11:13there and if so which ones those are or
- 11:16rather which public keys of which
- 11:18certificates those are and what I will
- 11:20do is I will now add trust anchors here
- 11:25and intentionally cut this off. So what
- 11:28this will in the end do by just having
- 11:29this empty trust anchors block this by
- 11:32default won't trust anything. So we kind
- 11:36of deny all network traffic if we would
- 11:38really just leave it like that. We can
- 11:39technically also try this. In order to
- 11:42do so we need to link this network
- 11:43security config in our Android manifest
- 11:46simply here in the application tag. We
- 11:48would want to have an Android oops not
- 11:50like that but Android network security
- 11:53config. And here we want to then link
- 11:55this from our XML files like this. If we
- 11:59now run this once more and we now also
- 12:02take a look here in lockcat and we now
- 12:05make a request to PL coding then you
- 12:08will see we instantly get a cert path of
- 12:10validator exception because the trust
- 12:13anchor for certification path was not
- 12:15found. So this in the end fails because
- 12:19with this config we technically disallow
- 12:22any sort of responses from any sort of
- 12:24server. Now that's of course not what we
- 12:26want. We want to pin our own server
- 12:29certificate here. So we allow the
- 12:32traffic we allow the responses in this
- 12:34case from PL coding but only from the
- 12:37certificate or from the public key of
- 12:40the certificate that the real PL coding
- 12:43site owns or is signed with after all.
- 12:47And the way this works is below this
- 12:48base config we want to have a domain
- 12:51config. So here we can now kind of
- 12:52override domain specific um behavior or
- 12:55rules and we can define such rules just
- 12:58for technically for the entire domain
- 13:01but you could even define this just for
- 13:03a few certain security critical
- 13:05endpoints. So we can say we have this
- 13:08for a certain domain and let's say we
- 13:10also want to include subdomains in this
- 13:12case. So we set this to true and the
- 13:14domain in this case will simply be PL
- 13:16code income. Then here we can also
- 13:18define certain trust anchors and this
- 13:20could be a certificates block where we
- 13:23can give this a specific source and
- 13:25simply say system so that the the
- 13:27certificates from the certificate
- 13:29authorities simply come from the system
- 13:31just the OS level predefined certificate
- 13:34authorities and then where the magic now
- 13:36really starts to happen is when we
- 13:37define a so-called pin set so a set of
- 13:41pinned certificates after all or s
- 13:43pinned public keys it's not the entire
- 13:45certificate that gets pinned or just a
- 13:47public key. But still, we typically call
- 13:49this certificate pinning. So that is
- 13:51what I will also use for the rest of
- 13:52this video. And here we want to define
- 13:54an expiration. This expiration could
- 13:57technically be the expiration of the
- 13:58certificate, but usually not. If your
- 14:02server is configured correctly and the
- 14:04certificate renewal is configured
- 14:06correctly so that it won't actually
- 14:08replace the private key here when the
- 14:10certificate is renewed, then this
- 14:13expiration here technically does not
- 14:14matter. And this is how you should
- 14:16configure it. But I really want to
- 14:17highlight this is usually not the
- 14:19default um for how these certificates
- 14:22are renewed. Um if you use something
- 14:24like let's encrypt certificates, this is
- 14:26the most popular free variant for
- 14:27getting such a certificate then the
- 14:29default config for that is actually not
- 14:32leaving the keys unchanged but actually
- 14:33also rotating them. So if you use that
- 14:36you would need an additional terminal
- 14:37flag or um like config setting for let's
- 14:40encrypt in this case that would really
- 14:42make sure these keys are left unchanged.
- 14:44But this expiration attribute here is
- 14:47kind of um a backup in case something
- 14:50really goes wrong because it will in the
- 14:52end let us define a date that is
- 14:54sometime in the in the future like uh
- 14:572027 let's say the first of 2027
- 15:01and then in here we can define a bunch
- 15:03of pins so specifically pinned public
- 15:06keys but the this pin set will only be
- 15:09applied until that exact date. So this
- 15:12means even if something breaks server
- 15:13set it even if we accidentally rotate
- 15:16our public private key pier and
- 15:18therefore our pin set of these previous
- 15:20keys would break and would disallow any
- 15:22sort of traffic our app can make to this
- 15:24domain then from this date it will work
- 15:27again because this pin set is only
- 15:29applied until then and at this date it
- 15:31will expire because you must imagine
- 15:33this is quite problematic if you if this
- 15:34accidentally happens and you have your
- 15:36Android app installed to tous thousands
- 15:39of users devices that really hardcode
- 15:41these pins we will define in a moment.
- 15:43But if then the server side changes
- 15:46something about that that breaks
- 15:47something on the client. The only way
- 15:49for you to really fix this is to get a
- 15:51new update with a new set of pins for
- 15:54the new certificate for the new public
- 15:56key on their devices. But if you've
- 15:59worked with Google Play before, if
- 16:00you've published apps before, you know
- 16:02how long that can take. You have to
- 16:04submit your app for approval. And even
- 16:06if it's approved, it technically has to
- 16:07end up on your users's devices. It's not
- 16:09like a website where you simply push an
- 16:11update and everybody who visits it from
- 16:12this point on will see it. But really
- 16:15like this deploying the app not just to
- 16:17Google Play but to all your users this
- 16:19can take a long while and up to then
- 16:21your app will pretty much be unusable if
- 16:24you break this and that's why there is a
- 16:25real danger attached to certificate
- 16:27pinning. So this is kind of a yeah a
- 16:29fallback or something that you could
- 16:31define from this point on certificate
- 16:34pinning won't be applied anymore for
- 16:36this particular pin set and from this
- 16:38point on in that kind of catastrophic
- 16:40case your app would start working again
- 16:41but this also means that before this if
- 16:44you define such an expiration you would
- 16:46actually have to update your app with a
- 16:48later expiration time because otherwise
- 16:50even if you don't rotate the keys it
- 16:53could still happen that you reach this
- 16:55date and it will simply not be applied
- 16:56anymore even though these pins would
- 16:58still be valid. So you just have to
- 17:00regularly publish updates with later
- 17:03expiration dates in this case if you
- 17:05stick to that or otherwise the
- 17:06certificate pinning approach will
- 17:07completely lose its point. But in the
- 17:10end we want to define a pin here or
- 17:12possibly multiple pins and so you have
- 17:14to define one such pin per domain or
- 17:17subdomain. We want to define a digest
- 17:20because these pins or the public keys
- 17:22here are hashed in the end with
- 17:24typically sha
- 17:26256. And then here for this pin we
- 17:29really just pass the hashed variant of
- 17:31our servers public key. There are
- 17:33certain terminal commands that in the
- 17:35end give you that. I will just show you
- 17:37one of them here that I actually use and
- 17:39that is here via OpenSL that at least
- 17:41works on Mac OS. Define your domain.
- 17:44This is the port for HTTPS. define your
- 17:47domain again and then um yeah you you
- 17:49just look for certain attributes here
- 17:52from the certificate and then we want to
- 17:54get the base 64 encoded version of that
- 17:56because that is what Android Studio is
- 17:58looking for. If we do this then
- 18:00something went wrong here with copy
- 18:02pasting. But if I actually show you my
- 18:05terminal that I've opened here then you
- 18:07can see we actually get something like
- 18:09this and if it looks like something like
- 18:11this and also ends with this equal then
- 18:13that means that that is what we are
- 18:14looking for and this is something I I
- 18:16did now here for the www variant but we
- 18:20need it for both. So with that or just
- 18:23the plain domain so that's something we
- 18:25want to copy. want to paste that in here
- 18:28and we want to do the same thing um for
- 18:31the plain domain variant which I've also
- 18:33retrieved here via the same command just
- 18:36replacing the domain in this case and
- 18:38this here would be the two hashes that
- 18:40we need and that we in this case pin
- 18:42that means if we now rerun our app with
- 18:45this updated config. So again we have
- 18:48linked this here and we have two
- 18:50requests on the one hand to PL coding
- 18:52and one on the other one to Google. If
- 18:54we make the one to Google then after a
- 18:57little moment we will actually get our
- 19:00network exception again because the
- 19:02trust anchor for the certification path
- 19:04was not found. So with our config we
- 19:07kind of disallow responses from any sort
- 19:09of domain except for our own one where
- 19:12we pin those certificates. So if we now
- 19:14actually do the same for the PL coding
- 19:17domain then you can see that's actually
- 19:19going through and we actually get our
- 19:20HTML here. So this response was properly
- 19:23retrieved. But if someone would now go
- 19:25ahead and would technically compromise
- 19:28the certificate authority that has
- 19:30signed the certificate for plcoding.com,
- 19:32then they would have their own
- 19:33certificate that would technically be
- 19:35considered valid by most devices because
- 19:37they trust that certificate authority,
- 19:39but not by our app because we say for
- 19:42this domain, we only trust certificates
- 19:45that match exactly these kinds of
- 19:47fingerprints. And because a new
- 19:49certificate will have its own public
- 19:50key, that won't work. And that's the
- 19:53whole point of certificate pinning. Now,
- 19:55I really want to say here this base
- 19:56config thing is only something I did in
- 19:58order to showcase what I wanted to
- 20:00showcase that certain traffic is
- 20:01disallowed that other certain traffic is
- 20:03allowed. But this is something you
- 20:05usually don't want to have as a config
- 20:07generally that you just disallow any
- 20:08sort of traffic. So normally you just
- 20:10have something like the domain config.
- 20:12You just define those pin certificates
- 20:14for your domain or you want to actually
- 20:15pin something with. But other than that
- 20:17with this base config it can be very
- 20:19very dangerous because maybe third party
- 20:21SDK is making a network call to some
- 20:23kind of URL as well and this would also
- 20:25be blocked like that. But with this
- 20:26config you can technically define
- 20:28exactly what is allowed in your network
- 20:30um policy and whatn not. If these kinds
- 20:33of system design level topics are
- 20:34actually something you want to get
- 20:35deeper into and you really want to learn
- 20:37making the right technical decisions and
- 20:39really understanding tradeoffs,
- 20:41approaching large projects
- 20:42systematically, then this kind of
- 20:44thinking I can help you get in our
- 20:46senior app developer mentoring. Down
- 20:48below this video there is a link where
- 20:49you can apply where we can take a look
- 20:50how this could work. We're doing this
- 20:52for four years really helping Android
- 20:53developers around the globe become
- 20:55really really confident technically and
- 20:57just help them get to the next level in
- 20:59their career. Maybe that could be
- 21:00something for you. So, check the link in
- 21:02this video's description. And other than
- 21:03that, thanks for watching. I'll see you
- 21:05back in the next video. Have an amazing
- 21:06rest of your week. [music] Bye-bye.
- 21:18[music]
About this transcript
This page contains the full transcript of Certificate Pinning - The MOST Important Security Measure for Network Traffic In Your App by Philipp Lackner, generated from the public captions YouTube serves with the video. The transcript has 4,042 words across 587 segments, with the original timestamps preserved so you can click any line to jump to that moment in the embedded player.
What you can do with it
Use the transcript to take notes, quote the speaker, build a study guide, generate a summary with ChatGPT or Claude via the YouTube Summary tool, or export it as a timed subtitle file with YouTube to SRT. You can also re-open it in the transcriber to translate the transcript into 100+ languages.
Free YouTube transcript tool
YouTube2Text is a free YouTube transcript generator — no signup, no daily limit. Paste any YouTube link and get the full transcript instantly, with timestamps, click-to-jump, translation to 100+ languages, AI prompts for ChatGPT, Claude, and Gemini, and exports to TXT, SRT, VTT, or Markdown.