1. Disable all logging about break-in attempts.
2. Do not have any common user names like "root".
Say you want to be able to log in as root from anywhere, just with a password. This is a wise idea; what if you need access, but are in a situation where you are not able to use a certificate?
Make up an alternative name like roto-rooter or whatever pops into your head. Install it into the password file as an alternative name for UID 0. (Make sure it appears later than the "root" entry!). Also edit the shadow file, making sure that the entry is duplicated for the alternative name.
Then in the sshd config file, use AllowUsers to allow only a whitelisted set of users. Here if you say "AllowUsers rotorooter", then the only user id that can authenticate is exactly that one, and it's mapped to UID 0 via passwd/shadow. Add any other accounts you would like to remotely access, giving them similar aliases if they happen to land into a commonly probed space, or are something that a targeted attacker could infer from knowing something about you.
Attackers do not probe the user ID space at all. They concentrate exclusively on probing the password spaces of common user IDs like root, admin, database, www-data, etc. If your system does not support any of those IDs, they are not on a trajectory to crack anything. Your rotorooter password could be "g0d" and they will not get in, if all they ever try is root.
A much better idea is to set up a non-root user and configure sudo correctly.
* https://www.stigviewer.com/stigs/red_hat_enterprise_linux_9/...
Anything added in front of your normal service also complicates access, since it’s non-standard. If you want a standard solution to solve all your needs for secure access of IP-based services, use IPsec and be done with it once and for all.
1. <https://en.wikipedia.org/w/index.php?title=Kerckhoffs%27s_pr...>
(Adapted from this old post: <https://news.ycombinator.com/item?id=39898061>)
And for logging in particular: Just switch the logging over to a temp file that lives in RAM (what disk thrash/write-amplification/SSD wear?), or even disable it altogether for failed login attempts.
We already know that there are great hordes of zombies outside of the castle, banging on the doors and the blocked-off spaces where the windows once were, picking away tirelessly. That's been a constant for many years. Documenting their continued persistence is pretty meaningless. None of it is actionable, or stoppable. It's just going to keep happening. Recording attempts from valid users is also largely without merit; it also just looks like noise, and we've got other ways to troubleshoot stuff that breaks without maintaining a long list of zombie attacks to peruse.
If a zombie actually manages to get in, then that's pretty important to keep track of; log that. But the attempts don't mean anything and have not meant anything for a very long time.
(When the word comes forth that the zombies are gone and the noise has ceased, it will be broadcast so far and wide that even the most noise-deafened sysadmins will find it impossible to ignore. In that seemingly-impossible unlikelihood, we can then resume recording attempts to log in with ssh.)
Appeal to authority?
In the real world, it doesn't matter. Anything that makes the attacker's life harder is fair game. Stupid dogmatic sheep-like mindlessness only leads to "herd exploitability".
also complicates access
That's the whole point.
IPsec is way more complicated to set up than this (or other VPN solutions like Wireguard or OpenVPN for that matter), and doesn't even completely solve that problem, because your ipsec port is open. Although, admittedly, there are probably less bots looking for ipsec than ssh.
The reality is that there are basically two ways to operate SSH:
(1) You can, because OpenSSH is the significant remote service with the literal best track record of any remote service, just disable passwords and let SSH run in 22/tcp exposed to the Internet. Probably stop logging people scanning you; there's nothing you're going to do about it, so it's not real information.
(2) You can keep SSH behind WireGuard, an even simpler security protocol with an even better security story (though: OpenSSH is quite solid), which is designed to not to chat with counterparties that don't have keys, even to do negotiation.
Everything else is performative.
I'd incline towards option (2).
The broadcasting of the versioning information does constitute a potential leakage of information that could be useful to an attacker. Even if we contrast this to something like mTLS, the client certificate doesn't come until fairly late in the handshake, so there is still information that can be cleaned from the ServerHello from an unauthenticated inspector. This is also the case with QUIC since it piggybacks off the general TLS handshake.
I think the issue is, for a known set of systems, can you create communications between them that are oblivious/non-discoverable to non-authorized systems. I think the answer is yes, but it requires an out-of-band key agreement protocol. Wireguard is an example. However, the problem of out-of-band key agreement can't really be ignored.
I think the article's method is somewhat valid. I also think it is non-ideal for only doing source IP based rulesets, especially in the world of IPv4 and NAT being prevalent.
The goal should be to have your complex layers sitting in front of simpler, easier-to-review lines of defence. Once you get to something like an open connection to ssh, the potential attack surface would be orders of magnitude larger, even though it’s more mature and closely scrutinised.
In the first iteration the IPv6 got polled by a handful of attackers as soon as the letsencrypt certificate was published. In the second iteration I just picked another IPv6 address from the /64 and made ssh.example.com to point to it. This should work until the attackers start guessing subdomain s...
I’m reading this thread and wondering if I’m missing something, why people are still talking about port knocking, port obfuscation, and fail2ban.
I use a cloud VPS. I ssh in via Tailscale. The cloud provider firewall blocks all incoming connections except traffic originating from Cloudflare IP ranges on port 443. My host plays dead to portscans. I check with nmap periodically. I have a break-glass backup terminal login option via my cloud provider dashboard (secured with MFA) in case Tailscale failed and needed investigation and repair.
This has worked well for me on AWS and Oracle Cloud. It’s quick and easy to set up. You need a timed service to refresh the ingress IP ranges, but any LLM could spit that out in a second.
Realistically, fwknop is more likely to have a vuln than OpenSHH. Last release was two years ago and the readme dates back twelve :/ Time will tell.
seed=`date +%s%N`; ( echo "secretknock-20260811|$seed"|sha512sum ; echo $seed ) | xargs nc -u 192.168.1.1
It is not secure as hmac and it can be 'trivially' brute forced, but don't require extra tools (probably nc not always readily available).On other hand if threat vector includes network monitor with ability to replay i would use wireguard to wrap ssh traffic.
Nothing is good enough on its own.
Geoblocking, fail2ban, port obscurity, SSH keys, limiting logins to specific usernames, not using your public internet nickname, putting things behind CloudFlare tunnels or WireGuard, wildcard DNS obscurity, 2FA... There are many options.
Defense in depth is the only way to put services on the internet.
Port 22 is getting perma-DDOSed on public IPv4 addresses so use it at your own peril but at least for now most bots don't bother port scanning everyone.
1. "would you know if you got breached?" 2. "would you have any reaction time?"
A simple solution that answers this: https://github.com/64mb/ssh-login-alert-telegram/blob/master...
UDP was designed as no-guarantee of delivery. Why would you rely on it for this important feature?
This was before WireGuard and Tailscale, so the main option for remote access was IPsec or OpenVPN, which are both more complicated than most people want to deal with.
* Disable SSH root login
* Disable password login and use only certificates
* Enable fail2ban
This have been worked for more than ten years and never been hacked.
I never understand the need for port knocking.
Restrict it to the networks where authorized users will be connecting.
So, I have this nft script which works alongside Firewalld:
$ systemctl enable --now nftables
$ cat /etc/nftables/portknock.nft
table ip portknock {}
delete table ip portknock
table ip portknock {
set knocked {
type ipv4_addr
flags timeout
timeout 6s
gc-interval 2s
}
# Before conntrack: record the knock, then drop the packet.
chain prerouting_knock {
type filter hook prerouting priority raw; policy accept;
tcp dport 12334 fib daddr type local tcp flags syn counter add @knocked { ip saddr } drop
}
# Decision chain for port 41444. Every branch is counted so that
# `nft -a list table ip portknock` shows which path traffic took.
chain gate_41444 {
# Established/related sessions pass unconditionally.
ct state established,related accept
# Host-local. Rarely matches: host-originated traffic is DNATed in
# the output hook before it reaches prerouting. Kept as a safeguard.
iifname "lo" counter accept
# Podman containers reaching the published port (hairpin).
ip saddr 10.88.0.0/16 counter accept
# Trusted subnets.
ip saddr { 10.0.0.0/24, 10.1.0.0/24 } counter accept
# Knocked within the last 6 seconds.
ip saddr @knocked counter accept
# Default deny. If THIS counter is 0 and the accept counters are
# also 0, the chain is not being reached at all -- investigate.
# Do not assume the gate is working just because nothing got in.
counter drop
}
chain prerouting_gate {
type filter hook prerouting priority mangle; policy accept;
tcp dport 41444 fib daddr type local jump gate_41444
}
}
Then on the client side, I can use anything to send the knock, but usually I just script it out with `ssh` like this: $ ssh -p 12334 -o ConnectTimeout=1 "${sServer}" &> /dev/null
$ sleep .5
$ ssh -o 'ExitOnForwardFailure=yes' -o 'StrictHostKeyChecking=no' -o 'LogLevel=ERROR' -fp 41444 -R "${iPort}:localhost:22" -T "${sServer}" "sleep 14d"
The biggest benefit is that it doesn't require any non-standard tooling. If you have an SSH client and know the rules, you can connect.Yeah, it doesn't have all the "cryptographic signatures" of the article; at the same time, it doesn't have some "random" 3rd-party application that faces the internet and directly controls firewall rules that way.
It's still an OpenSSH server with key-auth only. I'm not worried about someone carefully watching my traffic and finding it. I just need Internet bots not connecting to it a million times a second.
Unless it's an April Fool joke, in June.
1. Disable password auth, only public key auth should be enabled
2. Block public access to SSH entirely, use a VPN instead (Tailscale & co. make this trivial)
And 2 is entirely optional for most people reading SSH guides who just want a server to host their hobby project. Let's be real, you're probably not reading the auth logs anyway so they don't need to be clean, and if someone discovered an OpenSSH public key auth bypass vulnerability, they absolutely wouldn't waste it on you. Just let those dumb scanners go at it all day, they're not getting in.
And a little tangent: fail2ban is 100% placebo and does nothing except clean up the logs a bit. I don't understand why it's still a common recommendation for beginners, it's a relic from the past when bruteforcing was still a concern because people used password auth.
> to be unreachable: no banner, no version string,
> It works, but it has a real weakness: