{"version":3,"sources":["webpack:///./src/posts/2016-03-05-HTTP-Public-Key-Pinning-with-Spring-Security.md"],"names":["_frontmatter","layoutProps","MDXLayout","DefaultLayout","MDXContent","components","props","mdxType","href","target","parentName","isMDXComponent"],"mappings":"+QAMO,IAAMA,EAAe,GAOtBC,EAAc,CAClBD,gBAEIE,EAAYC,IACH,SAASC,EAAT,GAGZ,IAFDC,EAEC,EAFDA,WACGC,E,oIACF,mBACD,OAAO,YAACJ,EAAD,iBAAeD,EAAiBK,EAAhC,CAAuCD,WAAYA,EAAYE,QAAQ,cAG5E,uDACA,0OACuB,iBAAGC,KAAK,qCAAqCC,OAAO,UAApD,YADvB,2SAG6D,iBAAGD,KAAK,mDAAmDC,OAAO,UAAlE,QAH7D,gBAIA,6CACA,0WAEA,sBAAQC,WAAW,KAAnB,YAFA,0BAEuE,iBAAGF,KAAK,wEAAwEC,OAAO,UAAvF,gBAFvE,qGAGA,sRAEA,uHACA,uBAAK,kCAAMC,WAAW,OAAU,CAC5B,UAAa,kBADZ,uPASL,0CAAyB,sBAAQA,WAAW,KAAnB,mBAAzB,mHACe,sBAAQA,WAAW,KAAnB,6DADf,iFAEyB,sBAAQA,WAAW,KAAnB,6DAFzB,+BAGF,sBAAQA,WAAW,KAAnB,mBAHE,mMAIsE,sBAAQA,WAAW,KAAnB,qBAJtE,2BAKO,sBAAQA,WAAW,KAAI,0BAAYA,WAAW,UAAvB,qDAL9B,sDAMA,4EACA,mEACA,4NAGA,yCACA,uBAAK,kCAAMA,WAAW,OAAU,CAC5B,UAAa,kBADZ,gHAIL,kEACA,uBAAK,kCAAMA,WAAW,OAAU,CAC5B,UAAa,kBADZ,mJAIL,4CACA,uBAAK,kCAAMA,WAAW,OAAU,CAC5B,UAAa,kBADZ,gJAIL,mDACA,uBAAK,kCAAMA,WAAW,OAAU,CAC5B,UAAa,kBADZ,qMAIL,qEACA,sBACE,kBAAIA,WAAW,MAAf,sCAA2D,0BAAYA,WAAW,MAAvB,iDAC3D,kBAAIA,WAAW,MAAf,sCAA2D,0BAAYA,WAAW,MAAvB,kDAE7D,qDACA,sCAAqB,sBAAQA,WAAW,KAAnB,aAArB,iDAAoH,0BAAYA,WAAW,KAAvB,oBAApH,sGACwD,sBAAQA,WAAW,KAAnB,sBADxD,gDAC+J,sBAAQA,WAAW,KAAnB,qBAD/J,yCAGA,uBAAK,kCAAMA,WAAW,OAAU,CAC5B,UAAa,kBADZ,wdAcL,uBAAK,kCAAMA,WAAW,OAAU,CAC5B,UAAa,iBADZ,6aAsBTN,EAAWO,gBAAiB","file":"component---src-posts-2016-03-05-http-public-key-pinning-with-spring-security-md-95499d80dbabe8eabe14.js","sourcesContent":["import React from 'react'\n /* @jsx mdx */\nimport { mdx } from '@mdx-js/react';\n/* @jsx mdx */\n\nimport DefaultLayout from \"/opt/build/repo/src/templates/posts.js\";\nexport const _frontmatter = {};\n\nconst makeShortcode = name => function MDXDefaultShortcode(props) {\n console.warn(\"Component \" + name + \" was not imported, exported, or provided by MDXProvider as global scope\");\n return
;\n};\n\nconst layoutProps = {\n _frontmatter\n};\nconst MDXLayout = DefaultLayout;\nexport default function MDXContent({\n components,\n ...props\n}) {\n return \n\n\n

{`What kind of sorcery is this?`}

\n

{`HTTP Public Key Pinning, or short HPKP, is a security mechanism which allows HTTPS websites to resist impersonation by attackers using mis-issued or otherwise fraudulent certificates.\nThis was standardized in `}{`RFC 7469`}{` and creates a new opportunity for server validation.\nInstead of using static certificate pinning, where public key hashes are hardcoded within an application, we can now use a more dynamic way of providing this public key hashes.\nOne caveat to remember is that HPKP uses a Trust On First Use (`}{`TOFU`}{`) technique.`}

\n

{`How does this work?`}

\n

{`A list of public key hashes will be served to the client via a special HTTP header by the web server, so clients can store this information for a given period of time.\nOn subsequent connections within previous given period of time, the client expects a certificate containing a public key whose fingerprint is already known via HPKP.\nI `}{`strongly`}{` encourage you to read `}{`this article`}{` by Tim Taubert, where he explains what keys you should pin and what the different tradeoffs are.`}

\n

{`Imagine you want to terminate the connection between the client and a malicious server for your main domain and all of your subdomains, but also want to be notified when such events happen.\nIn the next paragraph you can find the implementation details.`}

\n

{`The web server needs to send following header to the connecting client with the first response`}

\n
{`Public-Key-Pins:\n    max-age=5184000;\n    pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\";\n    pin-sha256=\"E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=\";\n    report-uri=\"https://example.net/hpkp-report\";\n    includeSubdomains\n`}
\n

{`By specifying the `}{`Public-Key-Pins`}{` header the client MUST terminate the connection without allowing the user to proceed anyway.\nIn this example, `}{`pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\"`}{` pins the server's public key used in production.\nThe second pin declaration `}{`pin-sha256=\"E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=\"`}{` also pins the backup key.\n`}{`max-age=5184000`}{` tells the client to store this information for two month, which is a reasonable time limit according to the IETF RFC.\nThis key pinning is also valid for all subdomains, which is told by the `}{`includeSubdomains`}{` declaration.\nFinally, `}{`report-uri=\"https://www.example.net/hpkp-report\"`}{` explains where to report pin validation failures.`}

\n

{`So how can we implement this with Spring Security?`}

\n

{`Retrieving the list of public key hashes`}

\n

{`We first need to get a list of public key hashes.\nCurrently the standard only supports the SHA256 hashing algorithm.\nThe following commands will help you extract the Base64 encoded information:`}

\n
{`From a key file`}
\n
{`openssl rsa -in my-key-file.key -outform der -pubout | openssl dgst -sha256 -binary | openssl enc -base64\n`}
\n
{`From a Certificate Signing Request (CSR)`}
\n
{`openssl req -in my-signing-request.csr -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64\n`}
\n
{`From a certificate`}
\n
{`openssl x509 -in my-certificate.crt -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64\n`}
\n
{`From a running web server`}
\n
{`openssl s_client -servername www.example.com -connect www.example.com:443 | openssl x509 -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64\n`}
\n

{`For now we will assume we got 2 public keys:`}

\n \n

{`Configuring Spring Security`}

\n

{`As of version `}{`4.1.0.RC1`}{`, which will be released March 24th 2016, the `}{`HpkpHeaderWriter`}{` has been added to the security module.\nThe 2 easiest ways to implement this feature is either by `}{`Java configuration`}{` or by using the older, but still supported, `}{`XML configuration`}{`.\nBelow you can find both solutions:`}

\n
{`@EnableWebSecurity\npublic class HpkpConfig extends WebSecurityConfigurerAdapter {\n    @Override\n    protected void configure(HttpSecurity http) throws Exception {\n        http.httpPublicKeyPinning()\n            .addSha256Pins(\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\", \"E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=\")\n            .reportOnly(false)\n            .reportUri(\"http://example.net/hpkp-report\")\n            .includeSubDomains(true);\n    }\n}\n`}
\n
{`\n    \n\n    \n        \n            \n                d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\n                E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=\n            \n        \n    \n\n`}
\n\n
;\n}\n;\nMDXContent.isMDXComponent = true;\n "],"sourceRoot":""}