unscaled
Joined 11 years ago
Joined 11 years ago
Then the rest of the article explains why this is NOT a good feature in practice.
I don't think it's unworkable either, but this is one of these little thing that Go decided to do different and convinced its fans that this is a great idea and all the other languages where doing it wrong. After a couple of road bumps appeared, instead of admitting there are some advantages to having official package names, we're now told that everybody should just set up their own custom domain with an nginx server or a Go Vanity URLs forwarder to serve traffic for their GitHub-hosted packages.
Kotlin gets this right. On send/receive, you can use trySend or tryReceive if you want to avoid exceptions. Considering Kotlin also has coroutines and structured concurrency, concurrency in Kotlin feels more ergonomic to me than Go. At least if you want to get concurrent code with least amount of bugs and not just least amount of extra keywords.
XML Schema (just like JSON schema) did not. When we're talking about a "simple format" in terms of security we are talking about parsing footguns like these features, not about complexities that may exist with any wire format such as schema and data validation.
Were there any better formats for simple messages back in 2002?
I would argue that yes.
1. ASN.1 is horribly complex, but PKCS #7 (Cryptographic Message Syntax, a.k.a. CMS) was already established, and it was better than XML Signatures in one regard: it did not try to fuse the signed content with its envelope. But this probably wasn't he best choice.
2. If all you needed is a bag of keys and values, you could easily go with an RFC 822 style header + values format (which worked well for both email protocols and HTML). As a bonus S/MIME was already well established at this point, so you had an obvious way to sign this data.
3. Simple binary formats like XDR (used by NFS) or simple textual formats like LDIF or the RFC 822 header format mentioned above could be freely combined with any existing signature protocol that did not mandate structured data (i.e. every signature protocol in existence before XML Signature came in).
4. An even better approach of course, would have been to say no to fine-grained cryptographic agility[1]. That was a terrible mistake, but it was the default design choice back in 2002, and it's hard to single out OASIS. The JOSE/JWT authors should have known better though. You could have define a couple of ciphersuites/version, and a simple, fixed signature protocol for each version.
5. The best approach would have been to just avoid signatures completely and require TLS, but this wasn't viable back in 2002. Even OAuth 1.0 and OpenID 1.0, which came out several years later, included their own cryptographic signatures, but their schemes were still far simpler than SAML.
I think the key takeaway today is that SAML is no longer necessary today. TLS is not an option for secure web resources. There are no features of SAML that cannot be supported by OAuth or OIDC (only security misfeatures). All IdPs and most products support OIDC. In fact, OIDC is probably more well-supported than SAML.
SAML is only used because of enterprise inertia and self-inflicted FUD. As a professional, we should treat SAML with the the same disdain we've directed we've directed towards Internet Explorer 6. This is an insecure legacy technology that presents a drag on the entire industry.
---
[1] https://www.blockchaincommons.com/musings/musings-agility/
This flow is safe against CSRF, since no authentication data is carried together with the flow. The only other safety issue I can see is using target_link_uri for CSF. The spec clearly mentions that this URL has to be filtered or ignored by the RP.
Instead of treating the (horrible) technical implementation as a feature, it addresses the real user-facing feature: I want to be able to click on a link on my IdP dashboard and be redirected to the app. The login would still be seamless, since you already have an SSO session active with the IdP.
[1] https://openid.net/specs/openid-connect-core-1_0.html#ThirdP...
https://openid.net/specs/openid-connect-core-1_0.html#ThirdP...
OpenID Connect is basically OpenID reimagined on top of OAuth 2.0, with using JWT for the identity data.
The core OpenID Connect spec is still purely a federated identity standard. There are many other standards pushed by the OpenID foundation, but OpenID Connect itself was never meant to be anything more. The main feature differentiator from the OG OpenID is that it's built on top of OAuth, so you can add other features supported by OAuth (like authorization) ad-hoc.
1. It has the ill-conceived "alg": "none". But this feature made breaking JWT so easy and low stakes, that many libraries have removed this feature completely, or just disabled it by default.
Modern RFCs that mandate JWT use in servers (e.g. RFC 9068) often explicitly forbid this, and the latest BCP for JWT (RFC 8725) recommends that libraries only accept or generate tokens with "none" when the user _explicitly_ requests that. And yet, we're still seeing "alg": "none" vulnerabilities even to this day. I'm not sure if it made sense to support "alg": "none" in the first place, but if we ended up doing that, the RFC should have been much more strict about this.
2. The other issue is mixing up asymmetric and symmetric encryption. You can't embed the HMAC password directly in the user-generated message; but if the library is not built securely, it would just treat the public key itself as the HMAC key when it gets an HMAC alg in the header. This makes forging tokens quite trivial if the library is misconfigured.
JWT is not nearly as bad SAML and its designers learned some important lessons (simpler base format, no canonicalization or embedded signatures), but this is still a design-by-committee standard that didn't properly involve. The full JOSE standard (including JWA) is even worse, but fortunately JWA doesn't get used a lot.
Yes. But keep in mind KLOCs are not easily comparable across languages. Java is notoriously verbose. A 500KLOC codebase in Java would usually be half that size in Rust. If your argument is that large codebases makes life harder for agents, you should go with a less verbose language.
I'm not sure what "manual optimization" means (isn't it a bit of an oxymoron when the agent does it?), but if your agent has the proper tools (e.g. ast-grep, rg, semble) it can deal with large codebases. Would the agent create slop? Yes. But it wouldn't be worse on the slop that humans created on every moderately-sized Java project I've worked on.
> in fact, agent-written code in a low-level language gets pretty slow well below that size
I've never seen this happening. I've seen agents writing suboptimal Rust code (e.g. copies instead of Cow). But while this occassionally happens with Rust, I've never seen an agent optimizing for Java where necessary (e.g. using object pools to avoid GC churn). Java is not magic.
That part i s true.
> with newer Java versions the only real gap with Kotlin is null-safety
But that part isn't. Kotlin has:
- Structured Concurrency: Coming to Java sometime in the future, but it's been in preview for very long now.
- Standalone functions that don't have to live in classes
- Properties
- Property delegation
- Data classes: more powerful than records. Can be used for large DTOs that you can modify with copy(). Java needs something like Lombok to make records more useful.
- Extension methods
- Context parameters
- Operator overloading
- Implementation delegation
- Inline functions (which can receive returning closures and reified types)
- Block syntax (supports `it` for unnamed arguments)
- Sequence abstractions: more powerful and more efficient than Java streams due to the inlining and block syntax.
This is just a partial list, but Kotlin clearly has a lot of things that Java doesn't. If you only personally care about NPEs that's fine, but that's not the only thing.
> And that "team" nowadays may also consist of many AI agents.
And that's the part where the hireability arguments collapse. Sure Claude Code works pretty well with Java. It also works well with Typescript, Python, Go and Rust. It would use types on all of these languages, and run a type checker or LSP on the dynamic ones. And while Java is statically typed, Rust has a stricter type system that prevents some types of runtime bugs that Java's type system won't like data races and forgetting to release a resource.
https://github.com/uber-go/nilaway
Not exactly the same solution as JSpecify, since it doesn't rely on annotations, but it's also more ergonomic.
I'm not comparing this to "null-restricted types", since that's a draft JEP that hasn't made it even into a preview feature. Go also had multiple proposals for explicit nilability in types, and while they probably have less prospect of ever seeing the light of day compared to Project Valhalla, as things currently stand, Go is in the same position as Java: They are both extremely prone to NEPs out-of-the-box and they both have external tooling that can help you avoid them.
Java null checkers have more comprehensive coverage potential compared to Go, but Go is the more ergonomic one here. You don't need a single extra annotation on your code.
I get it why this seems like a less drastic change, but this saddens me. Kotlin solves more issues with the type system (smart casts, reified types, immutability by default), without sacrificing readability. Unless I can see a solution in Java that makes dealing with NPEs as easier for lazy developers as ignoring them, I don't consider it a solved issue.
1. Many services have old users with passwords that predate password-strength meters (or their ill-conceived brethren: password complexity rules). The service provider knows these passwords keep falling, and the cost of having to deal with stolen accounts is very real: customer support calls, reimbursements and investigation. But I've rarely seen services that force users to upgrade their passwords (even though it's a very easy solution). Whenever I've offered doing this myself, it was always shut down (either immediately or 3 years down the line) by a myriad of seemingly unrelated stakeholders.
2. To go further than this, companies can also know for certain that some credentials have been leaked by looking at password breach aggregators like Have I been Pwned and forcing users with affected accounts to change their passwords. That too, is rarely done.
3. 2FA (with SMS or TOTP) has existed for ages now, yet very few major non-financial services have made 2FA mandatory by forcing you to register an authenticator app or a verified phone number[1].
4. Webauthn was available in Chrome and Firefox in 2018, and got pretty widespread support by 2020. The "Passkeys" brand was not a thing yet, but the basic functionality was there and both hardware and software support was quite solid. It still took several years for services to even start offering Webauthn to users, beyond small and limited trials. The rationale was simple: UX around Webauthn was still rough, syncing and transferring credentials were still unsolved and the worst part was "What do we even ask the user to do?". The broad concept of passkeys is extremely confusing, but the non-concept we had before was far more confusing. Supporting Webauthn back in 2020 would have given tremendous security benefits for power users who could have understood it and deal with the rougher UX back then, but nobody wanted to take the risk of regular users setting up a passkey, losing it and locking down their account.
5. Now that passkeys are being supported by more and more services, you still don't see them being pushed very hard. Passkeys are great for the service provider, since they just kill a big category of security incidents, but even then you're see pretty conservative adoption. And I've never seen a single service forcing you to use Passkeys.
My point in all these examples is that most companies are extremely conservative here. Forcing users to do something that might confuse them, break their account or frustrate them is risky, since you may lose a very real chunk of your customer base. Sometimes you have to do this, the costs from keeping the old way or the benefits or forcing the change have to be high enough to justify that. Think about how long it took for companies to drop support for IE6. The cost was high, but as long as it still had a sizable market share, it was hard to do. Google was probably the first major company to take steps towards killing IE6 support, and this was famously entirely bottom-up, and was done by engineers either hiding it from their bosses or tricking them[2].
With this trend. I personally find the scenario where non-copyable attested passkeys are forced on everyone unlikely. OP keeps mentioning Netflix, but streaming services are a rather special case, most service providers would get very little benefit from restricting users to an attested non-copyable passkey. Why would they risk all that friction for... nothing at all?
The more real risk with attestations (and we're already started seeing it) is that some services (namely banks) will use attestations to limit you to use their own shitty app instead of using a proper passkey.
---
[1] Keep in mind I'm only talking about companies that already had password-based accounts without 2FA. Companies that started out with a simple username and password are rarely forcing their users to add 2FA. The farthest they generally went is sending you an OTP code or link on a verified email address they already had, and this is usually only done for sensitive operations, a new browser and/or a suspicious location.
Email OTPs, notably, aren't 2FA by definition, since your Email address might be only password-protected, and at the worst case (and excruciatingly common) scenario it might be sharing exactly the same password as your service. Companies would love to have all their users using a stronger solution, so they can stop having to deal with all these pesky credential stuffing botnets, but not at the cost of losing a non-negligible portion of their customer base.
[2] https://blog.chriszacharias.com/a-conspiracy-to-kill-ie6