Why does SSH send 100 packets per keystroke?

19 hours ago (eieio.games)

The 2023 timing obfuscation is a nice case study in security defaults vs edge cases. Most SSH users won't notice 100 packets per keystroke - it's noise in the bandwidth budget. But for high-frequency terminal apps, it becomes the dominant cost. At 2000 concurrent players updating 80x60 chars at 10fps, a custom protocol might be the right answer regardless of obfuscation settings.

  • You'd think the cover traffic would automatically cut out once the connection reached a certain rate though.

  • Just think of the trees burnt in the name of security!

    • Each of our devices spents a lot of energy dedicated to encryption. By now, all disks you did not set up manually are most likely encrypted and hardly any unencrypted package will travel out of your network. That's not to mention the tons of load and dedicated hardware we have just to terminate https and scan traffic for suspicious activity or the hardware being replaced because it's internal security triggered/broke.

      In a perfect world, we could send all traffic completely unencrypted and never scan for a malicious payload, saving all that energy and hardware. But we do not live in that world and drawing the line with this minor, mostly unintrusive security feature seems strange.

      3 replies →

> Obviously forking go’s crypto library is a little scary, and I’m gonna have to do some thinking about how to maintain my little patch in a safe way

This should really be upstreamed as an option on the ssh library. Its good to default to sending chaff in untrusted environments, but there are plenty of places where we might as well save the bandwidth

  • "where we might as well save the bandwidth"

    I come from a world (yesteryear) where a computer had 1KB of RAM (ZX80). I've used links with modems rocking 1200 bps (1200 bits per second). I recall US Robotics modems getting to speeds of 56K - well that was mostly a fib worse than MS doing QA these days. Ooh I could chat with some bloke from Novell on Compuserve.

    In 1994ish I was asked to look into this fancy new world wide web thing on the internet. I was working at a UK military college as an IT bod, I was 24. I had a Windows 3.1 PC. I telnetted into a local VAX, then onto the X25 PAD. I used JANET to get to somewhere in the US (NIST) and from there to Switzerland to where this www thing started off. I was using telnet and WAIS and Gopher and then I was apparently using something called "www".

    I described this www thing as "a bit wank", which shows what a visionary I am!

  • It sort of already is. This behavior is only applied to sessions with a TTY and then the client can disable it, which is a sensible default. This specific use case is tripping it up obviously since the server knows ahead of time that the connection is not important enough to obfuscate and this isn't a typical terminal session, but in almost any other scenario there is no way to make that determination and the client expects its ObscureKeystrokeTiming to be honored.

    • What's a concrete threat model here? If you're sending data to an ssh server, you already need to trust that it's handling your input responsibly. What's the scenario where it's fine that the client doesn't know if the server is using pastebin for backing up session dumps, but it's problematic that the server tells the client that it's not accepting a certain timing obfuscation technique?

      1 reply →

  • Threats exist in both trusted and untrusted environments though.

    This feels like a really niche use case for SSH. Exposing this more broadly could lead to set-it-and-forget-it scenarios and ultimately make someone less secure.

  • +1... Given how much SSH is used for computer-to-computer communication it seems like there really should be a way to disable this when it isn't necessary.

  • Relying on not advertising some feature for it is very janky way to do it.

    The proper fix would be adding option server-side to signal client it's not needed and have client side have option to accept or warn about that

  • It's not just the pointless chaff, the SSH protocol is inherently very chatty, and SFTP even more so. The solution, for a high-performance game, is don't use SSH. Either run it over Wireguard or grab some standard crypto library and encrypt the packets yourself. You'll probably make a few minor mistakes but unless the other player is the NSA it'll be good enough.

    For that matter, why does it need to be encrypted at all? What's the threat model?

    If there really is a genuine need to encrypt and low latency is critical, consider using a stream cipher mode like AES-CTR to pregenerate keystream at times when the CPU is lightly loaded. Then when you need to encrypt (say) 128 bytes you peel off that many bytes of keystream and encrypt at close to zero cost. Just remember to also MAC the encrypted data, since AES-CTR provides zero integrity protection.

Very interesting, I hadn't heard of this obfuscation before so it was well worth clicking.

Another good trick for debugging ssh's exact behavior is patching in "None" cipher support for your test environment. It's about the same work as trying to set up a proxy but lets you see the raw content of the packets like it was telnet.

For terminal games where security does not matter but performance and scale does, just offering telnet in the first place can also be worth consideration.

Funny to see this fixed in 2023 and the side effects. Back in 2004, before I focused on performance, I did some security work including inter-keystroke latency analysis of captured SSH sessions to estimate the commands typed:

https://www.brendangregg.com/sshanalysis.html

The 2023 patch should finally fix that 2004 issue.

I don't see how Claude helped the debugging at all. It seemed like the author knew what to do and it was more telling Claude to think about that.

I've used Claude a bit and it never speaks to me like that either, "Holy Cow!" etc. It sounds more annoying than interacting with real people. Perhaps AIs are good at sensing personalities from input text and doesn't act this way with my terse prompts..

  • Even if the chatbot served only as a Rubber Ducky [1], that's already valuable.

    I've used Claude for debugging system behavior, and I kind of agree with the author. While Claude isn't always directly helpful (hallucinations remain, or at least outdated information), it helps me 1) spell out my understanding of the system (see [1]) and 2) help me keep momentum by supplying tasks.

    [1] https://en.wikipedia.org/wiki/Rubber_duck_debugging

    • A rubber ducky demands that you think about your own questions, rather than taking a mental back seat as you get pummeled with information that may or may not be relevant.

      11 replies →

    • Rubber Ducky is a terrific name for a GPT.

      Also, always reminds me of Kermit singing "...you make bath time so much fun!..."

  • AIs are exceptional at sensing personalities from text. Claude nailed it here, the author felt so good about the "holy cow" comments that he even included them in the blog post. I'm not just poking this, but saying that the bots are fantastic sycophants.

  • It's like I keep saying, it probably wasn't a good idea to give our development tools Genuine People Personalities...

Genuinely asking: Wasn't the reason this happens kind of obvious in the first place?

Wow, I did not realize that SSH did that. Good to know, and it makes sense as a default, because the people who need it need to have it on by default. But I think I'm going to be turning that off, because it's a security measure that doesn't make sense for my particular environment:

1) I'm pretty much never typing secrets into an SSH tunnel; these days if there's a secret I need to transmit over SSH I'm going to be copying and pasting it, which will not reveal info from keyboard timing. (Or rsync'ing a file, which ditto).

2) I'm not in a high-security environment where nation-states have an interest in sniffing my keystrokes.

3) I often open SSH connections to servers in other continents. Those underwater cables have massive bandwidth, but they're also in constant use by thousands upon thousands of people. So anything I can do to reduce my bandwidth by 100x is probably worth doing.

Any reason you can think of why I should not be setting ObscureKeystrokeTiming=no in my ~/.ssh/config?

  • I think those all have reasonable counterarguments:

    (1) This sounds brittle. Are you really going to have a good mental model about what's secret when using ssh and reliably refrain from typing those things? Seems to kinda defeat the idea of securing the channel. Also, as a collection your activities might be more confidential to you than single inputs, or correlated with your other activities outside ssh, etc - it's hard to keep a mental model of this as well. Aka optimism is not a form of security.

    (2) There isn't a reason to think this is a difficult attack that only a powerful adversary could mount. Seems like a college lab level thing to me. And very amenable to AI help as well. Also here optimism is not a form of security. It's a 25 year old attack[1] so there's a lot of existing research[2] around.

    (3) Saving 100x bandwidth on single keystrokes on an internet dominated by video traffic just because it's 100x doesn't make sense. Also it's good to cultivate a mindset that steers away from trading off security in favour of trivial resource savings.

    [1] https://www.usenix.org/conference/10th-usenix-security-sympo... (probably older stuff exists outside open literature)

    [2] eg https://crzphil.github.io/posts/ssh-obfuscation-bypass/

    • Bandwidth is not the problem when you are using mobile connections (4G, weaker 5G). Videos work just fine, but ssh can be painful already without keystroke obfuscation. The problem is latency. Especially when roaming abroad it can 100s of ms.

      Not sure whether the obfuscation is fully synchronous, i.e waiting for the server response before continuing. That would really kill it. Working with LTS distros I don't think I have seen it in practice yet. Need to try something modern on my next trip abroad.

      1 reply →

  • There's no way to know in advance if some leaked cleartext will provide enough information to an attacker to be useful. Attackers profit from making creative use of information they didn't have before.

    That said, plenty of people disable the most useful security features of SSH, like verifying host key signatures, with no ill-effects (as far as they know). For the majority of users, using Telnet and unencrypted HTTP would make no difference, as nobody's trying to hack them, and who really cares about privacy anyway?

    Did you know SSH has long-standing performance limitations due to its design that need patches to eliminate? It was never intended to be a high-performance tool. If you want really high performance, use Telnet. If you want real security, use SSH with all strong security options enabled plus a server using ContainerSSH with the OAuth2 plugin (SSH's keys are static, which can be captured and reused, which is bad). If you don't care either way, use SSH with the defaults.

  • > I'm pretty much never typing secrets into an SSH tunnel; these days if there's a secret I need to transmit over SSH I'm going to be copying and pasting it, which will not reveal info from keyboard timing

    One common secret that goes through a tty ssh connection is a sudo password. You are probably typing sudo command so without obfuscation the attacker can find out the sudo keystrokes, the command keystrokes and then the encrypted bytes of the password. They don't have the timing data to decode them as easily as the previous parts but if they record enough traffic they might be able to decrypt the password. But maybe they won't, because the ssh session key is probably different each time. Furthermore I don't know how many times they should capture your encrypted password to be able to decrypt it. Maybe it's unfeasible.

    Anyway, in case of the sudo password, if the attacker gets it what would happen? The attacker is hopefully not able to get a shell into the server. If they do they have different ways to get root privileges.

    By the way, I also copy and paste secrets from either the password manager or the clipboard, because nobody remembers long random strings. The only exceptions are the passwords of a few accounts.

    • sudo passwords are one of the things I'm copying and pasting from the password manager, because my shell account password is different on every system. But yes, if you type your sudo password without thinking about it, the timing attack might be feasible. (Though if you're laboriously copying a random password from a different screen, as I've had to do once or twice in situations where copy-and-paste was infeasible, the timing data will be useless as it's about 500 ms between keystrokes no matter what the previous keystroke is. Which is an interesting way to accidentally defeat this attack.)

You can also use TCP_CORK to reduce the number of packets without any increased latency.

Disabling TCP_NODELAY would also reduce number of packets + be portable & simpler to implement - but would incur a latency penalty.

  • Haven't heard of TCP_CORK, very interesting.

    For people who don't feel like googling it:

    1. You TCP_CORK a socket

    2. You put data into it and the kernel buffers it

    3. If you uncork the socket, or if the buffer hits MSS, the kernel sends the packet

    Basically, the kernel waits until it has a full packet worth of data, or until you say you don't have any more data to send, and then it sends. Sort of an extreme TCP_YESDELAY.

    See https://catonmat.net/tcp-cork for where I learned it all from.

  • Oh wow - I've never heard of TCP_CORK before. Without disabling pings I'd still pay the cost of receiving way more packets, but maybe that'd be tolerable if I didn't have to send so many pongs. This is super handy; excited to play around with it.

    I am aware of TCP_NODELAY (funny enough I recently posted about TCP_NODELAY to HN[1] when I was thinking about it for the same game that I wrote about here). But I think the latency hit from disabling it just doesn't work for me.

    [1] https://news.ycombinator.com/item?id=46359120

    • I missed that thread originally, the post and the comments where a good read, thank you for sharing.

      I got a kick out of this comment [0]. "BenjiWiebe" made a comment about the SSH packets you stumbled across in that thread. Obviously making the connection between what you were seeing in your game and this random off-hand comment would be insane (if you had seen the comment at all), but I got a smile out of it.

      [0] https://news.ycombinator.com/item?id=46366291

      2 replies →

  • Can you explain how TCP_CORK helps here? The chaff packets are spaced 20ms apart and sent per socket, so I don’t see how TCP_CORK could help unless it coalesced across 20ms intervals? But coalescing is clearly not an option for the intended obfuscation effect of the original feature.

    • It is unrelated to SSH, it is a generic TCP thing.

      "hello world" fits in a single TCP packet, but the kernel might end up sending one packet containing "hello" and another packet containing " world". It is completely opaque to userspace.

      TCP_CORK lets userspace decide when packets are dispatched. You get to control whether "hello world" is sent across 1 packet or 11 packets.

      1 reply →

Wait, go back to the first sentence:

> I am working on a high-performance game that runs over ssh. The TUI for the game is created in bubbletea 1 and sent over ssh via wish.

> The game is played in an 80x60 window that I update 10 times a second. I’m targeting at least 2,000 concurrent players, which means updating ~100 million cells a second. I care about performance.

High performance with ssh and wish? For sure not. Rather use UDP over secure sockets. Or just normal sockets. Even Claude would come up with much faster code than the ssh/wish nonsense. Or mosh, but this also too complicated.

  • The author wanted people to be able to just "ssh mygame", no? In that sense, ssh was a design requirement.

    • I didn't think about such throwback to the 80ies. Could be, yes. But then he cannot control the ssh option, and with 2000 users, maybe 10 would set it. I don't think so.

>In 2023, ssh added keystroke timing obfuscation. The idea is that the speed at which you type different letters betrays some information about which letters you’re typing. So ssh sends lots of “chaff” packets along with your keystrokes to make it hard for an attacker to determine when you’re actually entering keys.

Why not just add random "jitter" to the keystroke packets, but keeping just the 1 actual packet?

In 2023, ssh added keystroke timing obfuscation. The idea is that the speed at which you type different letters betrays some information about which letters you’re typing. So ssh sends lots of “chaff” packets along with your keystrokes to make it hard for an attacker to determine when you’re actually entering keys.

Now that's solving the problem the wrong way. If you really want that, send all typed characters at 50ms intervals, to bound the timing resolution.

  • > send all typed characters at 50ms intervals

    Wouldn't this just change the packet interval from 20ms to 50ms? Or did you mean a constant stream of packets at 50ms intervals, nonstop?

    I think the idea behind the current implementation is that the keystrokes are batched in 20ms intervals, with the optimization that a sufficiently long silence stops the chaff stream, so the keystroke timing is obfucated with an increased error bar of 20ms multiplied by number of chaff packets.

    • I assume the problem, such as it is, relates to the fact that a real human typing in 20-50ms would generate a few characters at most but a program could generate gobs of data. So automatically you know what packets to watch. Then you know if there were more the likely keys were in set X, while if there were fewer the likely keys were in set Y.

      So a clock doesn't solve the problem. The amount of data sent on each clock pulse also tells you something about what was sent.

      The Chaff packets already fire on a timer. They inject random extra fake keystrokes so you can't tell how many keystrokes were actually made. The only other way I can think of to solve that is by using a step function: Send one larger packet (fragmented or the same number of individual packets) on each clock pulse if the actual data is less than some N where N is the maximum keystrokes ever recorded with some margin. Effectively almost every clock pulse will be one packet (or set of packets) of identical size. Of course if you do that then you'll end up consuming more data over time than sending random amounts of packets.

Well, security is the #1 consideration for SSH, but if the author doesn't need security, why use ssh?

For example, "nc" (netcat) is pre-installed on all platforms where ssh is.

  • Depends on what kind of security. They might care about connection integrity. If a faulty (or malicious) router in-between client and server starts malforming packets, `nc` will display those malformed packets. SSH will only show you what the server intended, or nothing.

  • I seem to hit this logic often recently for some reason.

    There are two issues with it:

    - a primary is not a totality: if "security is the #1 consideration for SSH", that implies there's a #2, maybe even a #3 and so on consideration. So the question that follows becomes tautological: "but if the author doesn't need security, why use ssh?" -> surely for one or more of the #2, #3, etc. considerations, right?

    - overabstraction (*): you ended up strawmanning the author. What they had issue with was keystroke timing obfuscation, which is a privacy feature. Timing attacks are (in part) a privacy concern, and privacy is a security concern, yes, but security is not just privacy concern, and privacy concerns are not just about timing attacks; these groups are not equal. For example, they might very well want the transmitted keypresses themselves to remain confidential, or they might very well want to retain cryptographic assurance of their integrity. These are security features they can continue to utilize by sticking with SSH.

    All of this is to say, it's not even necessarily them using SSH for a hypothetical #2 or #3 (...etc...) reason, but likely because they still very much want to make use of large chunks of #1, which disabling keypress obfuscation does not actually rid SSH of, only at most weakens it in ways they clearly seem to be okay with.

    (*) although if I zoom out enough, this is once again just "a primary is not a totality", just implicitly

  • > For example, "nc" (netcat) is pre-installed on all platforms where ssh is.

    This is technically incorrect, because Windows now includes SSH too!

The reliance on LLMs is unfortunate. I bet this mystery could gave been solved much quicker by simply looking at the packet capture in Wireshark. The Wireshark dissectors are quite mature, SSH is covered fairly well.

  • I'm anti-LLM in most cases, but:

    > I bet this mystery could gave been solved much quicker by simply looking at the packet capture in Wireshark.

    For some people who are used to using Wireshark and who know what to look for, probably yes. For the vast majority of even technical people, probably not.

    In my case, I did a packet capture of a single keystroke using tcpdump and imported it into Wireshark and I get just over 200 'Client: encrypted packet' and 'Server: encrypted packet' entries. Nothing useful there at all. If I tcpdump the entire SSH connection setup from scratch I get just as much useful information - nothing - but, oddly, fewer packets than my one keystroke triggered.

    So yeah, I dislike LLMs entirely and dislike the reliance on LLMs that we see today, but in this case the author learned a lot of interesting stuff and shared it with us, whereas without LLMs he might have just shrugged and moved on.

    • And thats a huge downside when people howl about "Encryption everywhere! ".

      Try debugging that shit. Thats right, debugging interfaces aren't safe, by some wellakshually security goon.

      You want a real fun one to debug, is a SAML login to a webapp, with internal Oauth passthrough between multiple servers. Sure, I can decrypt client-server stuff with tools, but server-server is damn near impossible. The tools that work break SSL, and invalidate validation of the ssl.

      Yes, Esri products suck. Bad.

      5 replies →

  • Unfortunately with SSH specifically, the dissectors aren't very mature - you only get valid parsing up to the KeX completion messages (NEWKEYS), and after that, even if the encryption is set to `none` via custom patches, the rest of the message flow is not parsed.

    Seems because dumping the session keys is not at all a common thing. It's just a matter of effort though - if someone put in the time to improve the SSH story for dissectors, most of the groundwork is there.

    • Interesting, I thought it was possible to decrypt SSH in Wireshark a la TLS, but it seems I'm mistaken. It still would have been my first goto, likely with encryption patched out as you stated. With well documented protocols, it's generally not too difficult deciphering the raw interior bits as needed with the orientation provided by the dissected pieces. So let me revise my statement: this probably would have been a fairly easy task with protocol analysis guided code review (or simply CR alone).

      1 reply →

  • Sure it could have been, if you knew about SSH packet inspectors in Wireshark...

    The author didn't, and used a general tool to their aid - why is that unfortunate?

  • Asking an LLM about SSH (hint: the two S-es stand for security) would tell you why only having packet capture in Wireshark isn't going to reveal shit.

  • obviously OPs empirical and analytical rigor are top notch. He applied LLMs in the best way possible: fill gaps with clumsy command line flags or protocol implementations. Those aren't things one needs to keep in their head all the time.

  • Way to gatekeep. God forbid people use tools to help them investigate instead of knowing the exact approach to take.

    • My thoughts exactly. The OP used AI to get a starting point to their investigation, then used their skills to improve their game, with actual (I guess according to the article itself) proof of that, as opposed to just approving changes from the LLM.

      This looks like an actual productivity boost with AI.

    • What I suggested (mistakenly so, see my revised suggested approach in response to one of your siblings) is the exact opposite of gate keeping.

    • ChatGPT gaslit the OP telling it there was no such thing as keystroke chafing. So yes, in this case it would have been better to do the work oneself.

  • How much are you staking on that bet?

    • Well, I spent a good part of my career reverse engineering network protocols for the purpose of developing exploits against closed source software, so I'm pretty sure I could do this quickly. Not that it matters unless you're going to pay me.

      6 replies →

    • Sigh.

      I'm still waiting for a systems engineering tool that can log every layer, and handle SSL the whole pipe wide.

      Im covering everything from strafe and ltrace on the machine, file reads, IO profiling, bandwidth profiling. Like, the whole thing, from beginning to end.

      Theres no tool that does that.

      Hell, I can't even see good network traces within a single Linux app. The closest you'll find is https://github.com/mozillazg/ptcpdump

      But especially with Firefox, good luck.

      1 reply →

> That 20ms is a smoking gun - it lines up perfectly with the mysterious pattern we saw earlier!

Speaking of smoking guns, anybody else reckon Claude overuses that term a lot? Seems anytime I give it some debugging question, it'll claim some random thing like a version number or whatever, is a "smoking gun"

  • Yes! While this post was written entirely by me, I wouldn't be surprised if I had "smoking gun" ready to go because I spent so much time debugging with Claude last night.

    • Serious question though, since AI seems to be so all capable and intelligent. Why wouldn't it be able to tell you the exact reason that I could tell you just by reading the title of this post on HN? It is failing even at the one thing it could probably do decently, is being a search engine.

      1 reply →

  • Or the "Eureka! That's not just a smoking gun, it's a classic case of LLMspeak."

    Grok, ChatGPT, and Claude all have these tics, and even the pro versions will use their signature phrases multiple times in an answer. I have to wonder if it's deliberate, to make detecting AI easier?

    • A computational necromancer has likely figured out a way to power a data center by making Archimedes spin in his grave very fast.

  • Without knowing how LLM's personality tuning works, I'd just hazard a guess that the excitability (tendency to use excided phrases) is turned up. "smoking gun" must be highly rated as a term of excitability. This should apply to other phrases like "outstanding!" or "good find!" "You're right!" etc.

  • I'm working on a little SRE agent to pre-load tickets with information to help our on-call and I'm already tired of Claude finding 'smoking guns'.

  • You might see certain phrases and mdashes ;-) rather often, because … these programs are trained on data written by people (or Microsoft's spelling correction) which overused them in the last n years? So what should these poor LLMs generate instead?

  • They love clichés, and hate repeating the same words for something (repetition penalty) so they'll say something like "cause" then it's a "smoking gun" then it's something else

  • I don't think claude has even once used this in my conversations (Claude Desktop, Claude Code, Voice conversations...) Sycophancy, yes absolutely!

    Maybe it has something to do with your profile/memories?

  • smoking gun, you're absolutely right, good question, em dash, "it isn't just foo, it's also bar", real honest truth, brutal truth, underscores the issue, delves into, more em dashes, <20 different hr/corporate/cringe phrases>.

    It's nauseating.

  • > Speaking of smoking guns

    Oh shoot! A shooting.

    So the TL;DR of this post is: don't change this setting unless you know what you're doing.

> I am working on a high-performance game that runs over ssh.

Found your problem.

But it is an interesting world where you can casually burrow into a crypto library and disable important security features more easily than selecting the right network layer solution.

  • Yea UDP is technically more performant, but then you need a crypto layer + reliable message delivery layer + bespoke client. Using a plain old SSH client is cool.

    However, there are existing libraries for exactly this use case - see https://github.com/ValveSoftware/GameNetworkingSockets

    I guess QUIC libraries would also work.

    • its not really a question of 'udp performs better'. in tcp we have to live to head-of-line blocking on losses and congestion control. if you don't care about receiving every packet, but only the most recent, then udp is a good choice.

      running without congestion control means that you avoid slowstart. but at a certain rate you run into poorly defined 'fairness' issues where you can easily negatively impact other flows. past that point, you can actually self-interfere and cause excessive losses for yourself.

      quic uses congestion control, but uses latency estimates and variance as a signal to back off. it still imposes an ordering on a per-stream basis. so it might not be ideal either.

      sctp has a mode which supports reliable and unordered, which might be something to consider

      so really - if you care about latency and have a different reliability model, its worth unpacking all these considerations and using them to select your transport layer or even consider writing a minimal one yourself

      2 replies →

Or you could use anycasting to terminate SSH sessions on the moral equivalent of one of a number of geography based reverse proxies and then forward the packet over an internal network to the app server over a link tuned for low latency. The big guys already do something similar with HTTP over TLS for DDoS protection and to limit end to end latency on TLS.

Granted... it would increase the cost (since you're adding reverse proxies) but it would be a quick way to get acceptable latency, rudimentary DDoS protection, and you could try different connection options independent of the main app's logic.

It would be hard to estimate how much latency you're adding with a SSH2 reverse proxy in this case, but it's probably lower than one might think.

The idea of letting Claude loose on my crypto[graphy] implementation is about the most frightening thing I've heard of in a while [though libnss is so craptastic, I can't see how it would hurt in that case.] But I loved this write-up. It was readable and explained the problem the OP was encountering and proposed solutions well.

  • > Or you could use anycasting to terminate SSH sessions on the moral equivalent of one of a number of geography based reverse proxies and then forward the packet over an internal network to the app server over a link tuned for low latency.

    I've been thinking about some stuff like this! Not being able to put my game behind Cloudflare[1] is a bummer. Substantial architectural overhead though.

    > The idea of letting Claude loose on my crypto[graphy] implementation is about the most frightening thing I've heard of in a while [though libnss is so craptastic, I can't see how it would hurt in that case.]

    I hear you, but FWIW the patch I was reverting was trivial (and it's also in the go crypto library, which is pretty easy to read). It's a couple-of-line change[2], and Claude did almost exactly what I would have done (I was tired and would have forgotten to shrink the handshake payload).

    [1] This isn't strictly true, Cloudflare spectrum exists, but its pricing is an insane $1/GB last I checked.

    [2] https://cs.opensource.google/go/x/crypto/+/833695f0a57b30373...

    • Nice, but shouldn't the behaviour change be behind a config setting? And it's not clear what the intent of the change is. Implementing PING/PONG seems different from what you said you were trying to do. And it's section 1.8 of the OpenSSH [PROTOCOL] reference, not section 1.9.

      But... before you think I'm trying to be negative... good on you. I wish you well. Getting crypto/security code into open source projects can be a slog as people frequently come out of the woodwork, so don't get discouraged.

      And the more I think about this... there's plenty of examples out there about doing HTTP based reverse proxying, but essentially zero for SSH proxying, so if you do that, it would make a great blog post.

It's wonderful to see LLM's being used to increase the programming community's general quality level of work, as more things become worth doing.

Funny that this comes up today! I was just looking into adding a keyboard monitor to my website (I have a goal of making my 'contact me' page have oddly specific information). I wouldn't show the actual keys, just show a blinking light when there's activity, but I guess the timing really could expose quite a lot of information.

I did add a trackpad monitor though. It shows my raw MacBook trackpad data.

https://varun.ch/contact/

The really mysterious part is how ~10,000 packets per second costs ~20% of a core. That would mean SSH is bottlenecking in its code at ~50,000 packets per second per core which would be ~500 Mbps per core (assuming full packets) which is ludicrously slow. It is trivial to do 10x that packet per second rate. Is SSH really that poorly designed?

  • > It is trivial to do 10x that packet per second rate.

    When making this statement, are you taking into account that SSH encrypts the traffic by default?

    • I do not know where people get the idea that encryption is that slow. Standard AES hardware acceleration instructions do ~25 Gbps per core (on a 2023 CPU) which is ~50x that rate [1]. I have heard modern cores can do ~40-50 Gbps, but I have not been able to find any independent benchmarks of that. Even the Intel i5-2500, a CPU from 2011, averages ~10 Gbps which is ~20x that rate. Even unaccelerated encryption can do ~2-5 Gbps in pure software which is 4-10x the SSH rate.

      And in this situation, the amount of encrypted payload in each packet is 36 bytes which is ~40x less than a full packet of ~1500 bytes. You would almost surely hit packet per second limits before you hit payload throughput limits at these small sizes.

      Encryption is slow when compared to data throughput you can get with a properly designed transport stack, but that is because it is in comparison to 100 Gbps per core even with no hardware offload. Anything less than ~10 Gbps/1 million packets per second (ignoring other bottlenecks, so only the software transport is the limit) is not merely unoptimized, it is pessimized.

      [1] https://calomel.org/aesni_ssl_performance.html

    • doing a gigabit takes ~35% of single core to saturate my 1Gbit ethernet. On i3-3250 which is 12 years old CPU

      Your assumptions are way off

Not related to SSH, but does the eieio.games website make anyone else's monitor flicker? When the website is fullscreen it overwhelms something. I thought my monitor's backlight was going.

I wonder if this is the same reason why Microsoft's Remote SSH plugin on VS Code is so flaky even with a decent internet connection. Every couple of months I try to give it another go and give up due to the poor keyboard latency I inevitably experience. And the slow reconnects whenever I glance away from my computer monitor briefly. This is on a fiber connection with a 20ms ping to the remote machine.

  • You surely mean the latency in its embedded terminal and not the code editor, right? I use VSCode’s remote SSH specifically so that code editing doesn’t suck. It really does not.

    • You're right, the latency is in the embedded terminal. Perhaps it is trying to run SSH inside SSH. Still, the disconnects are a pain too.

Hmm, if the author is doing something high performance, they should probably use whatever mosh is doing to update the screen, not ssh.

  • That would require end users to install additional software though, which they do not want

    • Oh, true, ssh is not just the protocol, but also the name of the client software.

      Though I would suggest to make mosh available, too. Many nethack servers are available via mosh and ssh. (And in an earlier age, telnet.)

@eieio: whatever email protection you're running is triggering on the extension info. For example I see:

> And they’re sent to servers that advertise the availability of the [email protected] extension. What if we just…don’t advertise [email protected]?

  • Is it possible that this is on your end?

    The extension is "ping@openssh.com." It shows up in the blog reliably for me across several browsers and devices.

"The smoking gun!" got me laughing, i am not a native english speaker and only ever seen that expression from Claude, and who knew? Its gaining popularity!

Just replace it with zeromq with curvemq.

I could vibecode an SSH zmq daemon in an afternoon.

> Keystroke obfuscation can be disabled client-side.

please never do that (in production)

if anyone half way serious tries they _will_ be able to break you encryption end find what you typed

this isn't a hypothetical niche case obfuscation mechanism, it's a people broke SSH then a fix was found case. I don't even know why you can disable it tbh.

  • That doesn't sound right to me. This obfuscation isn't about a side-channel on a crypto implementation, this is about literally when your keystrokes happen. In the right circumstances, keystroke timing can reduce the search space for bruteforcing a password [1] but it's overstating to describe that as broken encryption.

    [1] https://people.eecs.berkeley.edu/~daw/papers/ssh-use01.pdf

    • THANK YOU!

      I'm baffled about this "security feature". Besides from this only being relevant to timing keystrokes during the SSH session, not while typing the SSH password, I really don't understand how can someone eavesdrop on this? They'd have to have access to the client or server shell (root?) in order to be able to get the keystrokes typing speed. I've also never heard of keystroke typing speed hacking/guessing keystrokes. The odds are very low IMO to get that right.

      I'd be much more scared of someone literally watching me type on my computer, where you can see/record the keys being pressed.

      1 reply →

  • They literally explain the mechanism in the post and then explain why the security tradeoff made sense for their ssh game………

  • It is to prevent timing attacks but there are many ssh use cases where it is 100% computer to computer communications where there is no key based timing attack possible.

    • There is an argument that if:

      - you are listening to an SSH session between devices

      - and you know what protocol is being talked over the connection (i.e. what they are talking about)

      - and the protocol is reasonably predictable

      then you gain enough information about the plaintext to start extracting information about the cipher and keys.

      It's a non-trivial attack by all means but it's totally feasible. Especially if there's some amount of observable state about the participants being leaked by a third party source (i.e. other services hosted by the participants involved in the same protocol).

      3 replies →

    • I haven't given this more than 5 seconds of thought, but wouldn't it make sense to only enable the timing attack prevention for pseudo-terminal sessions (-t)?

  • The fix seems kind of crazy though, adding so much traffic overhead to every ssh session. I assume there's a reason they didn't go that route, but on a first pass seems weird they didn't just buffer password strokes to be sent in one packet, or just add some artificial timing jitter to each keystroke.

    • I'm just guessing but this chaff sounds like it wouldn't actually change the latency or delivery of your actual keystrokes while buffering or jitter would.

      So the "real" keystrokes are 100% the same but the fake ones which are never seen except as network packets are what is randomized.

      It's actually really clever.

I find it disturbing.

One thing you notice if you have ADSL is that some services are built as if slower connections matter and others are not. Like Google's voice and audio chat services work poorly but most of the others work well. Uploading images to Mastodon, Bluesky, Facebook, LinkedIn, Instagram and Nextdoor is reliable, but for Tumblr you have to try it twice. I don't what they are doing wrong but they are doing something wrong and not finding out what they're doing wrong because they're not testing and they're not listening to users.

Nobody consulted me about their decision not to run fiber by my house. If some committee decides to make ssh bloated they are, together with the others, conspiring to steal my livelihood and I think it would be fair for me to sue them for the $50k it would take to run that fiber myself.

It's OK if you work for Google where there is limitless dark fiber but what about people in African countries?

It's the typical corporate attitude where latency never matters: Adobe thinks it is totally normal that it takes 1-5s for a keystroke to appear when you are typing into Dreamweaver.

  • I agree with your general point that most companies/projects do a terrible job optimizing for slow computers/networks, but OpenSSH is from the OpenBSD people, who are well-known for supporting ancient hardware [0]. Picking a random architecture, they fully support a system with only 64MB of memory [1], and the base install includes SSH. So I suspect that OpenSSH is fairly well tested on crappy computers/networks.

    [0]: https://www.openbsd.org/plat.html

    [1]: https://www.openbsd.org/landisk.html#hardware

  • There's a good chance you have other options. Regardless of how you feel about the company's head, Starlink would probably be one of them, with likely better performance than you're dealing with on ADSL.

    But you cannot just sue a company because their network connected software doesn't work well on slow networks. Let alone a project like OpenSSH. It would be like me suing a game studio because my PC doesn't meet their listed minimum requirements to play the game.

    • Hey, it is one thing to buy a new computer, it is another thing to ask people to move.

      A better analogy is a bank redlining neighborhoods. The cost to run fiber to difficult rural locations pays itself easily if you look at a 25-year time span and is an order of magnitude less than building a new housing unit on the West Coast.

  • You're not ok with a security/privacy tool using defensive techniques because of ... the lack of fiber in Africa?

    • My backyard but people will take Africa more seriously than anywhere in the US 2 miles from the end of cable.

  • The openssh team does not owe you anything.

    If you want a “1990s” mode, add it yourself or pay some to do it for you.

  • > One thing you notice if you have ADSL

    This is funny to me, because ADSL used to be the fast thing, as opposed to dialup modems.

  • You just opened a huge nostalgia portal, never thought that Dreamweaver would still be around, I used that somewhere around 2003 I believe. Good memories

    • Frankly I wish there was an HTML editor that delivers on what it promised. I mean, markdown is almost as rife with edge cases as YAML and somehow the link syntax still eludes me. If we could “just” template by merging at the DOM level and had decent HTML editors the world would be a different place. But yeah, Adobe probably thinks Dreamweaver isn’t worth maintaining just as they seem to think Photoshop is barely worth maintaining (they keep adding AI features that sorta work but the foundations seem to be much worse than Illustrator)

>very confidently told me that my tcpdump output was normal ssh behavior:

I mean, for modern version of Openssh it's not exactly wrong. The failure was to tell you why that is the normal behavior.

>>> That makes a lot of sense for regular ssh sessions, where privacy is critical. But it’s a lot of overhead for an open-to-the-whole-internet game where latency is critical.

Switching to telnet instead of SSH might be an option.

> I am working on a high-performance game that runs over ssh.

Step one, run https://www.psc.edu/hpn-ssh-home/introduction/ instead Step two, tune TCP/IP stack Step... much later: write your own "crypto". (I'm using quotes because, before someone points out the obvious, packets-per-keystroke isn't, itself, a cryptographic algorithm, but because it's being done to protect connections from being decrypted/etc, mess with it at your own peril.)

If security doesn’t matter then why not use telnet or something else besides ssh instead of forking a security library?

I loled and closed the article after 'I am working on a high-performance game that runs over ssh.'

Vibe coders man...

> I am working on a high-performance game that runs over ssh.

WAT. Please no.