惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
V
V2EX
WordPress大学
WordPress大学
U
Unit 42
I
InfoQ
A
About on SuperTechFans
宝玉的分享
宝玉的分享
J
Java Code Geeks
博客园 - 司徒正美
爱范儿
爱范儿
Engineering at Meta
Engineering at Meta
G
Google Developers Blog
人人都是产品经理
人人都是产品经理
小众软件
小众软件
Microsoft Security Blog
Microsoft Security Blog
L
LangChain Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Hugging Face - Blog
Hugging Face - Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
aimingoo的专栏
aimingoo的专栏
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Last Week in AI
Last Week in AI
腾讯CDC
Recent Announcements
Recent Announcements

Neil Madden

Are we any closer to the Quantum Apocalypse? Java sealed classes and exhaustive pattern matching Mythos and its impact on security Maybe version ranges are a good idea after all? Why I don’t use LLMs for programming Looking for vulnerabilities is the last thing I do Were URLs a bad idea? Monotonic Collections: a middle ground between immutable and fully mutable Fluent Visitors: revisiting a classic design pattern Rating 26 years of Java changes No, no, no. You’re still not doing REST right! Streaming public key authenticated encryption with insider auth security Are we overthinking post-quantum cryptography? A look at CloudFlare’s AI-coded OAuth library The square roots of all evil Digital signatures and how to avoid them Machine Learning and the triumph of GOFAI Galois/Counter Mode and random nonces SipHash-based encryption for constrained devices Newsletter A controversial opinion about REST API design Regular JSON I still don’t really get “hash shucking” Entity authentication with a KEM Book review: The Joy of Cryptography A few programming language features I’d like to see On PBKDF2 iterations A few clarifications about CVE-2022-21449 CVE-2022-21449: Psychic Signatures in Java Is Datalog a good language for authorization?
Java’s SSLContext protocol name is a footgun
Neil Madden · 2026-06-24 · via Neil Madden

This should be old news, but I keep seeing the same mistake crop up, so I thought I’d blog about it and spread awareness. In Java, if you want to configure TLS you generally start with an SSLContext. And you get an instance of this class by calling the static method SSLContext.getInstance("TLSv1.3"), specifying the version of the protocol you want to support. But typically a TLS connection supports other versions of the protocol, so what exactly does specifying “TLSv1.3” here mean? Probably not what you think it means…

The Java Security Standard Algorithm Names document doesn’t say much useful: “Supports […] TLS version 1.3; may support other SSL/TLS versions.” Well, which other versions? Later ones or earlier ones? That seems kind of important. It’s even vaguer if you don’t specify a version – the generic “TLS” identifier is specified as (my emphasis):

Supports some version of TLS; may support other SSL/TLS versions.

Useful.

OK, but what about the JSSE chapter in the Java Security Developer’s Guide. That seems at first glance to be more precise:

Like other JCA provider-based engine classes, SSLContext objects are created using the getInstance() factory methods of the SSLContext class. These static methods each return an instance that implements at least the requested secure socket protocol. The returned instance may implement other protocols, too. For example, getInstance("TLSv1") may return an instance that implements TLSv1, TLSv1.1, and TLSv1.2.

OK, that sounds promising! So, if I specify a version then that is taken as a minimum version and I may also get more recent versions? Great, sign me up!

Except, that is the exact fucking opposite of what the default SunJSSE provider does! When you specify “TLSv1.1” (for example), what the default provider does is treat that as a maximum TLS version. So the resulting SSLContext supports all versions of TLS up to (and including) 1.1, but nothing later. So if you have old code that requests version 1.1 and you try to connect to a modern server that only supports 1.2 and 1.3, then you’ll get a connection failure. And in modern Java, this will fail earlier because TLS 1.1 is disabled by default. If you specify “TLSv1.2” then you’ll just silently get a downgraded protocol for no good reason at all, when you probably thought you were being good and specifying a sensible minimum version.

It’s not just the default provider that does this, lots of others have followed the lead, including e.g., the Conscrypt/BoringSSL provider used by Android.

I suspect this behaviour exists because of a fear of breaking poorly-written software that baulks at unknown versions and doesn’t handle downgrades properly. But the problem is that many developers think it is best practice to specify a version when creating an SSLContext, and some security scanners even tell you to do so. In the best case, you then get code that is secure until the next major hole is discovered in TLS and v1.4 gets released. In the worst case you’ve silently implemented a self-inflicted protocol downgrade attack. I wonder how many Java apps were (and maybe still are) only supporting TLS 1.1/1.0 despite the underlying JDK supporting 1.2 or even 1.3?

Aside

I should stop here and mention a subtlety: this behaviour applies to client TLS connections only. Server-side SSL contexts completely ignore the protocol you specify here for the most part and go ahead and support everything.

So what should you do instead? Well there’s really no good answer here. Probably the best thing to do is to use the generic “TLS” identifier, which gets you an unspecified version of TLS, but which all providers I’ve looked at so far interpret as “sensible modern protocol versions”, i.e., TLS 1.3 and 1.2 (with 1.1 and earlier supported but disabled by default). There’s no guarantee at all of that behaviour, but there’s also no guarantee when you specify a version, so pick your poison.

(I’ve raised a bug for this, as it finally pissed me off enough, but my guess is they’ll either ignore it or fix the guide to be as vague as the standard names descriptions).