-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cryptographic Recommendation #1
Comments
Aside: If you could use libsodium, you could adopt what CMS Airship uses instead, which combines Ed25519 signatures (for authenticity), Merkle trees (for userbase consistency), and verifiable reproducibility to make infrastructure-based attacks miserable to pull off, and silent, targeted infrastructure attacks near-impossible. |
Strongly disagreed. A self-updater that isn't secured is a great avenue for deploying Trojans from trusted infrastructure. You'll essentially be creating a remote code execution backdoor without mandatory HTTPS and cryptographic signatures. Don't repeat WordPress's mistakes. |
Thank you so much for reviewing what I have here, @paragonie-scott! Alexpott of drupal.org posted a link to the CMS Airship blog post mere hours before your feedback here. I was probably going to be trying to get in touch with the author of that post tonight begging for guidance on the crypto aspects, and then you beat me to it! In addition to your observations here I need to think more about making master and signing keys and a revocation mechanism happen... HMAC was the best answer I came up with since I started looking into this a couple weeks ago, and I recognize the dependence on a shared secret is suboptimal. I definitely want to get it right the first time and not someday be responsible for hacked sites, so if there's a better way, by all means it should be used. To that end I'm trying to look into choices 2 and 3,
I note that you don't mention any particular ECDSA implementation, but do for RSA via phpseclib. In practice, should I interpret this to mean that I should use OpenSSL for ECDSA unless I have to fall back on phpseclib? (An interesting argument FOR phpseclib is that the CMS organization would be empowered to push fixes in it as well, for all sites, whereas the patch status of OpenSSL on a given site is a big question-mark.) I'm also not finding any information about the "over seck1p256" part? Yeah sorry, libsodium's not possible, I don't want to propose changing Drupal's system requirements. I also want to keep at the forefront the sites that will benefit the most from automatic updates - little operations on shared hosts that are at the mercy of the php build found there, with no continuing support from the firm that created the site years ago. |
I made that edit earlier because I wasn't absolutely sure that phpseclib offered deterministic ECDSA. However, I also wrote the wrong name down. You want secp256r1 not seck1p256 (which is actually named secp256k1). n.b. secp256r1 is also known as NIST P-256, which is what most people use for ECDSA. OpenSSL does support ECDSA, but I don't know if it supports RFC 6979. If it does, I can't figure out how to access that feature from PHP. See https://3v4l.org/E1C9Y Feel free to use:
OpenSSL's implementations shouldn't reuse nonces, so you probably don't need to care about these details. Recommended reading: Cryptographic best practices. |
Oh, by the way, I work for the company that published the referenced blog post. :) Shameless plug: If you opt for RSA, we wrote a library that makes RSA easy to get right. |
Two other asides,
Thanks |
The person receiving the SFTP credentials would need to have a 2048-bit RSA private key dedicated to encryption. The corresponding public key would need to be used to encrypt the SFTP credentials before they're uploaded. Encryption: use ParagonIE\EasyRSA\EasyRSA;
use ParagonIE\EasyRSA\PublicKey;
$publicKey = new PublicKey($publicKeyAsPEMEncodedString);
$encrypted = EasyRSA::encrypt($sensitiveCredentials, $publicKey); Decryption: use ParagonIE\EasyRSA\EasyRSA;
use ParagonIE\EasyRSA\PrivateKey;
$privateKey = new PrivateKey($privateKeyAsPEMEncodedString);
$stored = EasyRSA::decrypt($encrypted, $privateKeyObject); What you could do is: Encrypt the ciphertexts and then send them (over HTTPS!) to your central infrastructure. When a security-critical update is needed, run a script that decrypts each client's credentials. Make sure the private key is stored in a memory-mapped file rather than to disk, and Bonus: Use something like TAILS, which will run the entire OS in memory and leave nothing on the disk. The risks here are reduced to the realm of "nation state attacker", against which most systems are hosed anyway. Fortunately, such adversaries are both rare and their budgets typically mandate being used on targets of interest. (Unfortunately, WordPress, Drupal, and Joomla could be targets of interest to some advanced threats due to their market share alone.) Despite its name, EasyRSA's encryption is actually a hybrid cryptosystem consisting of:
This is ideal for arbitrary-length ciphertexts.
(I can't make any commitments that conflict with my time obligations to PIE's clients, of course, but I don't think this will be a problem at all.) |
Understood. I may well be the only person from the Drupal community to have ever written any code towards automatic updates, and that was yesterday, so at this rate it will be some time before there's something to review. I certainly wouldn't expect a firm commitment of time at some far future point. Nevertheless, this sounds promising! I get the sense from the Paragon blog post's review of CMSs that open source CMS developers haven't been doing a lot of collaborating with cryptographic consultants historically. Perhaps we will be able to get it right this time. |
Also worth mentioning: We wrote a comparison chart of various CMSes compared to the one we developed. It's obviously biased in that it only focuses on security features, but if you only compare the big three, it's rather informative. Outside auto-updates (which is very important), there are a lot of other items that addressing now will save a lot of pain going forward. Using real prepared statements, rather than emulated prepares, would net you another green checkmark. :) https://paragonie.com/blog/2016/06/php-security-platinum-standard-raising-bar-cms-airship You may also find it worth chatting with @dd32, who was working on a similar goal for WordPress (but obviously has to contend with their minimum version requirements, so I don't know if he's found a clear way forward). |
As an update for this, I'd like to recommend https://github.com/paragonie/sodium_compat for Ed25519 signatures for the automatic updates as well as This recommendation hinges on it being successfully audited by an independent third party, as per this issue. |
Thanks @paragonie-scott. I'm still working away at a standalone application for in-browser updates of whatever CMS you desire. The first goal is just manual/attended upgrades, since Drupal doesn't do that, but once that is done I'll be looking at automating update deployment again and circling back to the attendant security and crypto concerns. |
We've got an open issue for that one at https://www.drupal.org/node/2348931. |
FYI, sodium_compat 1.0 is now available, for both digital signatures and anonymous public-key encryption. It hasn't been audited, but all attempts to get a third party audit led nowhere, so this is the best we can do for now. |
Don't use HMAC here. Instead, use in order of preference:
The reason is simple: HMAC is a symmetric key message authenticity verification that, in order to verify, you must be able to generate signatures. If the Drupal installation can verify the HMAC, it must have the HMAC key. What prevents an attacker from obtaining the key and using it to forge an update containing a trojan?
It's the wrong tool for the job. (See this primer on core cryptography concepts for an in-depth explanation on which tools work for the job.)
In Drupal's case, you really can't depend on libsodium yet (because of the current installed userbase) but you certainly use phpseclib to solve the problem.
You can also use RSA/ECDSA keys to sign a Phar directly. We do this for random_compat.
The text was updated successfully, but these errors were encountered: