Please sign the jar
arnoldgeels opened this issue · 12 comments
Thank you for writing this great encoding library!
Please sign the jar, so that when I pull from maven, I can verify that the code can be trusted and was not altered.
Acknowledged, we'll aim for this next release.
@jeremylong could you kindly assist me with this? :)
@arnoldgeels - I think we need a bit of clarification here in terms of specifically what you are asking. As per my understanding based on this statement from https://maven.apache.org/repository/guide-central-repository-upload.html, I think that Maven Central requires GPG signatures on jars:
PGP Signature
When people download artifacts from the Central Repository, they might want to verify these artifacts' PGP signatures against a public key server. If there are no signatures, then users have no guarantee that they are downloading the original artifact.
To improve the quality of the Central Repository, we require you to provide PGP signatures for all your artifacts (all files except checksums), and distribute your public key to a key server like http://pgp.mit.edu. Read Working with PGP Signatures for more information.
(Note: The MIT PGP key server acts a bit flaky; I would suggest using one of these 2 URLs via GPG: hkp://pool.sks-keyservers.net or hkp://kerserver.ubuntu.com)
Also, when I look at this project's POM, they seem to be using maven-gpg-plugin to create the signatures. So perhaps the problem is that they didn't upload their public key used for signature verification to one of the public key servers so you are unable to verify the signatures. But that doesn't mean that it isn't signed, but only that they signature is next to worthless unless you can get the public key somewhere.
However, the other thing that you might be referring to--which is why I am asking--is you may be referring to signing 'tags' (e.g., 'git tag -s tagname ...'). Alternately, you could be referring to deploying code signing of the encoder-vers.jar file using a code-signing certificate from some CA and that you would verify via 'jarsigner' or some similar manner. (Note that this generally costs money even for open source projects; Let's Encrypt does not issue Code Signing certificates.)
That is, the succinct way that you phrased this leads to different possible interpretations so it is ambiguous.
I'm sorry my request was not clear. What I mean is that you sign the jar with jarsigner
. End users of your software, but also anywhere in the supply pipeline, one can run this command: jarsigner -verify encoder-1.2.3.jar
. Currently this will print jar is unsigned.
The goal is to make it print jar verified.
We sign the jar files in the software that we build ourselves. For third-party jars, it's best if the supplier signs the jar, so that end users can verify integrity was maintained during the entire supply chain.
You are correct: to sign a jar, you will need a code signing certificate. I hope OWASP already has such a certificate, otherwise you will have to purchase one.
My request is not about the PGP signatures that maven uses during uploads. I am also not asking you to sign tags. You are free to do these things, of course.
I agree this is important. The next release will include this. I am going to need help (maybe @jeremylong) to do a release especially if we sign.
@jmanico - ESAPI signed it's jars, way back in ESAPI 2.0GA IIRC. If you look at the current ESAPI pom.xml, there are still remnants there from the jar signing, in the profile on lines 856 through 942. I was one of the idiots who insisted on it back then, but now that I know that Maven requires jars be signed and that you can verify those if you wish with this Maven plugin (https://www.simplify4u.org/pgpverify-maven-plugin/index.html), separately signing the jars seems mostly redundant to me. I eventually saw it as an expense that OWASP did not need, it was a royal PITA because you had to remember the code signing cert every 2 years or so, etc. That's why even though I was the moron who originally suggested it, I'm admitting that it was not really providing us much. Note however, if you really want to do this, then you 1) need to also 'seal' all your packages within the jar file (see https://docs.oracle.com/javase/tutorial/deployment/jar/sealman.html) and 2) you probably should write some start-up code in a static initializer somewhere that verifies your jar's signature is valid (because you really shouldn't IMO, assume that developers will do this).
If @arnoldgeels really wants this, there is nothing to prevent his development teams from verifying the original signature that it was uploaded to Maven Central with and then after verifying that, to run jarsigner himself with his team's own signing key. But if he finds that not acceptable, I would ask "What is your threat model here?" that makes you feel like this is needed. If anything, I think I would ask the OWASP Java Encoder contributors to sign their commits. I think that goes further than signing jars. Signing jars would be a fine idea and not at all redundant if Maven Central didn't require digital signatures on the libraries uploaded to their repos, but since they do, I think that using jarsigner is largely redundant.
Just my $.02. -kevin
Hi @kwwall, thank you for expressing your opinion. To answer your question: the threat is that the software (jar) is modified anywhere in the supply chain. That threat is mitigated by signing the jar. In my case, as a software developer, the supply chain starts by pulling your encoder jar from maven, but it is then cached in Nexus, copied to a build system, packaged into a larger product, placed on our web site, downloaded by our customers, and finally installed on the end user's system. In all those places, anybody can verify the integrity of the software.
We sign our own jars, but we do not sign third-party jars, because it sends the wrong message, and there are (other! not yours!) components that no longer work when the jars are signed.
Signing commits secures parts of the OWASP supply chain, and I agree that this is important too, but it mitigates a different risk.
Signing on the upload helps, but it does not cover the entire chain.
Thanks!
@arnoldgeels I don't think that's precisely what @kwwall had in mind when asking about threats. For example, if your industry is say, insurance, you have a different set of attackers to worry about than some of my clients who work in the DoD space, who have to deal with nation-state level threats. The kinds of risk-analysis decisionmaking needs to be better understood.
The kind of analysis that Kevin's after, is does your company know who has access to the binaries at all the different points of your product flow? What kinds of access would they have to have in order to subvert the binary at each point? This is where rubber meets the road. This kind of exercise usually uncovers dark corners that Oz didn't realize were peeking from behind the curtain.
So I've worked in both banking and in the DoD space, jar signing simply hasn't been common for precisely the reason that by the time you account for how you'd have to develop an attack to get to--for example, the external-facing download server--you have access to far better fruits within the network than what you'd gain by patching with a backdoor. Like the source code itself. How are you protecting your keystores? How are you distributing your signing keys?
All I'm saying, is that even if you're protecting against a nation-state actor, if you have one set of default credentials active in your environment--say "admin:solarwinds1234" then I don't think that jar signing is the most cost-effective approach to securing your environment. Having worked in the DoD space, I've yet to run into a scenario where security elsewhere was so mature that the decision was made to enforce policies like this. Actually given the Solarwinds hack, it would be more likely that clients would perform their own hash validation outside of the jar signing process in the DoD space as jar signing infrastructure is usually poorly understood in the first place.
(If you want to get on a call to discuss, I can make myself available!)
(Kevin if I'm not helping here just tell me to shove off.)
I opened up a mess bringing up solarwinds here (but the email's away.) Because ideally, signing would prevent modifications at an update server like this. Unless the keystores were compromised which was really my main point.
@arnoldgeels -- Okay, I figured that "supply chain" attacks were where you were heading with this in regards to the 'WIYTM?' question, but I wanted to be sure before I responded and not make any assumptions.
Also, apologies in advance for this being so long-winded. If you want the TL;DR summary, I think someone sent you on a fool's errand if they think signing the OWASP Java Encoder jar is going to reduce supply chain attacks in any meaningful way.
You wrote:
We sign our own jars, but we do not sign third-party jars, because it sends the wrong message, and there are (other! not yours!) components that no longer work when the jars are signed,
I'm not sure what you mean by "it sends the wrong message". Surely, you use more FOSS jars than only the OWASP Java Encoder jar in your application and most of those jar providers--unless they happen to be security jars--are not going to even understand the risk mitigations (and understand, it is only mitigation and not remediation) that signing their jars can provide. So If you are using (say) 50 FOSS jars in your application, you will be lucky if you can get 2 or 3 of those jars signed, because not only doing so costs money which most FOSS projects have very little of, but also doing so and maintaining the signature, renewing the certificate, etc. is a royal PITA. (Been there, done that.) So, what are you going to do for all those other 45+ FOSS jars that you are using? (Not to mention any commercial ones.) Your choices is "send the wrong message" (your words, not mine) and have your organization sign the jars yourself as soon as you pull them down from whatever repo you are using (and you are only using an internal repo where you've previously vetted all the software and not allowing developers to pull code down directly from Maven Central, or worse, copy/paste code from Stack Overflow, right? ;) OR, more likely, keep on using them and not sign them at all. So you have a HUGE gap. If I'm an evil nation state, I'm not going to waste resources trying to backdoor something as like the OWASP Java Encoder. No, I'm going for bigger fish, like Spring Framework, or Jackson or any of the numerous Apache Commons projects that are much more broadly used.
Secondly, while I suppose you could use OWASP as an example and say "OWASP is now signing their jars, so this must be best practice and everyone else should follow their lead". Well, OWASP is pretty diverse, and I doubt you would get consensus on that from even the project leaders (myself included) and even if you could use that, it would take several years to get most of the FOSS providers on-board (short of government regulation). Also, you may or may not realize it, but Oracle and OpenJDK providers of Java do not sign the basic jars that they provide. So if you are truly concerned about supply chain attacks that modify software after installation, then you need to somehow verify these haven't changed either. Furthermore, verifying your build tool chain and your SBOM is not just a one-time occurrence. Its verification has to be a continuous process. It does little to run 'jarsigner -verify' once on each jar and then afterwards, never do anything else to verify that software artifacts integrity. The adversaries can attack any time, not just when you initially deploy to production.
Thirdly, you need to understand that jar signing is not a panacea. SolarWinds signed their executables and that didn't prevent the nation state supply chain attack against their clients. The malware attacked their build process and inserted the malware / backdoor before the code was signed, so that when it eventually was signed, it was signed with the backdoor already integrated into their Orion product so the signature itself was still valid. In fact, you may be surprised to learn that signing with jarsigner does not prevent an attacker from altering a jar file by either ADDING or deleting artifacts. E.g., I could add a new properties file or add or delete a .class file. What one cannot do (without the private signing key) is to alter one of the files in the jar. That would be detected by 'jarsigner -verify'. So in that regard, the detached GnuPG / PGP signatures used Maven Central are actually superior as they will detect any and all alterations to the jar file at all; those signatures are not limited the way that jarsigner's signatures are created.
All this is to say that I think this problem is much bigger than you and your manager likely realize. It's like removing a bucketful of water from the world's oceans. Does it reduce the amount of water in the oceans? Well, technically, yes. But for all practical purposes, no. Which is why I said in the initial TL;DR summary, this is a fool's errand. I am not the project lead for this project, but I will tell you that OWASP ESAPI will not be going down this path...at least not until the day that other more important things (everyone regularly signing commits, people using pgpverify-maven-plugin, and someone else absorbing the cost for the issuance and maintenance of a code signing certificate) are first taken care of. It is my personal belief that chasing the whole supply chain exploitations is like Don Quixote chasing windmills...noble and well-intentioned, but based on a misunderstanding of what the more realistic vulnerabilities are.
This of course is just my personal opinion and I'm not even sure if it is shared by other ESAPI contributors, nor do I speak for the contributors of the OWASP Java Encoder project. But I have learned over the years that signing jars / DLLs does not really significantly raise the bar with respect to security. I'd advise you to focus your $$ and effort elsewhere.
Best regards, -kevin
One Reason Why I Might Consider Jar Signing -- An Alternate Use Case
Note that this has nothing to do with the reason that @arnoldgeels requested that the OWASP Java Encoder project sign its jar(s), but since we were on the topic, I do think there is another use case for jar signing whose primary purpose is not related to ensuring integrity of the supply chain. Let me explain.
As a library provider, did you ever wish you could force clients using your library to update to the latest version so you wouldn't have to respond to issues about older versions either in GitHub issues or in emails or Stack Overflow posts, etc.? I know I have. I'd say at least a third of the posts in Stack Overflow about ESAPI concern versions that are at least a couple of years old and perhaps 4 or 5 releases behind.
As a long time project co-leader for the OWASP ESAPI library, I had often considered putting in a static initializer into one of the common classes (e.g., DefaultSecurityConfiguration
would be a good choice, or maybe Logger
) that would check how old the current release was and after (say) 1.5 years, start a 6 month countdown claiming that this library would stop working after (say) 2 years after the release date so that they would be compelled to use an updated version.
So why haven't I done that? Well, one reason is it's just too simple to patch the relevant .class file in the jar to skip that code and then re-jar everything. (It is simple enough to do that with C and C++ code; I know because in the late 70s / early 80s, that's how we issued our patches, using 'adb' (the original UNIX debugger, not Android Debug Bridge) to overwrite the binaries. There you had to understand assembler. In Java, it's way easier.)
But... if you signed the jar(s) and then had that same static initializer first check the signature of the jar (and throw something like an InitializationError
if the signature was invalid), you could at least prevent that trivial sort of tampering. Monkey with a .class file and that check of the validity of the jar's signature fails. You could also time the "expiration date" with the date that your code signing certificate happens to expire so you could maybe use that for justification of why you are expiring that version of the jar.
That means, if one wanted to bypass that check, they'd have to download the source code, alter it, and rebuild it and then distribute it internally themselves. (To prevent that version from being publicly shared, one would probably have to alter the FOSS license to prohibit doing that, which would likely require a whole unique license. I don't know about that as IANAL. I'll leave that one for @planetlevel and others with law degrees.) But my guess is that most development shops wouldn't want to go through all that trouble of building your FOSS library from source code themselves and distributing it only within their company.
This, of course, was always somewhat of a pipe dream and if one did that, it more likely would just cause you to lose clients or at least make them really mad at you, but I can't say that I haven't entertained that thought at times when I've spent time trying to answer questions about some ancient ESAPI release. But being somewhat lazy also helps me from doing really stupid things at times, so consider yourselves lucky.