Integrity checking for JavaScript

Including JavaScript files from a CDN can be beneficial in many ways as you don’t have to ship the code with your code and caching can be done by the browser of a proxy server. It also allows for injecting untrusted code into a web page as someone else is hosting the code you rely on. But Firefox, Chrome and Opera already support Subresource Integrity checking script and link tags. Hopefully both Safari and Edge (or Internet Explorer) will support it soon.

But how does it work? First let calculate the SHA256 hash of JQuery version 3.2.1 hosted by CloudFlare. Also keep in mind to verify this number with the official version offered by JQuery. In this example we download the minimized version of JQuery with curl and run it twice through openssl to generate the checksum and encode the result in base64 format.

$ curl -s https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js | openssl dgst -sha256 -binary | openssl enc -base64 -A
hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=

Now that we have the hash we can add the integrity attribute to the script tag and the prefix for the hash is “sha256-” to indicate the hashing used. From this point forward a browser that supports SubResource Integrity will require that the provided hash will match the calculated hash of the downloaded file.

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>

Beside SHA256 the specification allows for SHA384 and SHA512 to be used. Calculation is the same as with SHA256 and we only change the algorithm that openssl needs to use.

$ curl -s https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js | openssl dgst -sha512 -binary | openssl enc -base64 -A
3P8rXCuGJdNZOnUx/03c1jOTnMn3rP63nBip5gOP2qmUh5YAdVAvFZ1E+QLZZbC1rtMrQb+mah3AfYW11RUrWA==

We could put only the SHA512 hash in the attribute, but we can put multiple algorithm results in the same attribute by just splitting them with a space. This leaves a lot of room for proper lifecycle management of hashing algorithms as you can present multiple hashes when you switch to a better version instead of doing it big bang style and hope for the best.

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4= sha512-3P8rXCuGJdNZOnUx/03c1jOTnMn3rP63nBip5gOP2qmUh5YAdVAvFZ1E+QLZZbC1rtMrQb+mah3AfYW11RUrWA==" crossorigin="anonymous"></script>

The next step is to have a fallback when the CDN you rely on goes down or is serving corrupt files. You could add a second src tag as in the example below that tells the browser to use the Google CDN when CloudFlare has issues serving the correct files.

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js" noncanonical-src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4= sha512-3P8rXCuGJdNZOnUx/03c1jOTnMn3rP63nBip5gOP2qmUh5YAdVAvFZ1E+QLZZbC1rtMrQb+mah3AfYW11RUrWA==" crossorigin="anonymous"></script>

The next step is to get the Content-Security-Policy header correct, but for now only Firefox 49 and higher have the option to act on the require-sri-for attribute. This would basically force the browser to only load scripts and style sheets if the SRI-steps are successful, but many a lot of developers need to optimise their build pipeline to produce correct hashes and have correct monitoring to detect problems.

Password hashing

Tijdens het onderzoeken of een webapplicatie kon worden gevoed met standaard strings die voldoen aan het Modular Crypt Format, maar een snelle SQL-query leverde iets op wat al wijst naar een applicatie specifieke oplossing. Hiermee komt gelijk de vraag waarom elke developer weer het wiel blijft uitvinden, want dit maakt het vrij lastig om username/password data te synchroniseren of de applicatie direct te koppelen aan bijvoorbeeld LDAP.

SHA1X:6ca7fd38....

Een korte zoektocht in de code levert al vrij snel het volgende op, want het vermoede bevestigd. De vraag is dan ook wat hier aan te doen. Alle wachtwoorden worden dus standaard voorafgegaan door hun loginnaam wat het wisselen van een loginnaam onmogelijk maakt.

    /**
     * Encrypt a password in SHA1.
     *
     * @param string $pass The password to encrypt.
     * @param string $login A optionnal login.
     * @return string The encrypted password.
     */
    function encrypt_password($pass, $login = '') {
        if ($login) {
            return "SHA1X:" . sha1("$login:$pass");
        } else {
            return "SHA1:" . sha1($pass);
        }
    } // function encrypt_password

De bovenstaande functie maakt het inloggen met bv een e-mailadres in plaats van de username onmogelijk tenzij SHA1 wordt afgedwongen, maar dit is niet in te stellen in de configuratie. Aan de andere kant mist deze eigenlijk een goede salt oplossing om van dit probleem af te komen. Eerst maar eens bedenken en kijken of een stel algemene functies niet beter zijn plaats zijn welke zo meteen ook in andere applicatie te hergebruiken zijn. Want er zal ook een moment komen dat er zal moeten worden gemigreerd naar bijvoorbeeld SHA-256 zoals nu al wordt geadviseerd door NIST.

OpenPGP en SHA1

Dat MD5 namespace collissions had welke steeds serieuzere vormen begon aan te nemen was al een feit en voor SHA-1 waren ook al problemen te voorzien aan de toekomst. Helaas lijken voor SHA-1 de vorderingen sinds november 2008 en nu zo snel te gaan dat het een probleem begint te vormen zoals ook uit een posting is te halen:

Last week at eurocrypt, a small group of researchers announced a fairly serious attack against the SHA-1 digest algorithm, which is used in many cryptosystems, including OpenPGP. The general consensus is that we should be moving in an orderly fashion toward the theater exits, deprecating SHA-1 where possible with an eye toward abandoning it soon (one point of reference: US gov’t federal agencies have been directed to cease all reliance on SHA-1 by the end of 2010, and this directive was issued before the latest results).

Vooral de regel dat de Verenigde Staten van Amerika SHA-1 voor het einde van 2010 in de ban doet geeft mogelijk aan hoe serieus de zaak is. En met oa de MD5 problemen in veel X.509-certificaten nog vers in het achterhoofd wordt het misschien tijd om sommige hashing- en encryptiemethodieken in de ban te doen.

En hoewel het eerste gedeelte van de oplossing nog redelijk onschuldig is met de aanpassingen van de voorkeuren blijft de vraag was er bij het tweede gedeelte te winnen is nu. Zeker aangezien dat het een stuk verder ingrijpt dan nu mogelijk wordt voorgeschoteld. Om binnen 90 dagen over te stappen gaat veel problemen opleveren in the-web-of-trust waarbij de vraag misschien ontstaat of X.509-certificaten zoals van CACert geen betere lange termijn oplossing blijken. Maar een ding is wel duidelijk en dat is dat er meer speelt dan nu duidelijk is aangezien de VS op hoog tempo nu ook SHA-1 wil uitfaseren en sommige protocollen zoals DNS over wil hebben naar DNSSEC.