377 lines
15 KiB
Text
377 lines
15 KiB
Text
= Fortigate VPN SSL Hardening Guide
|
|
:source-highlighter: rouge
|
|
:title: Fortigate VPN SSL Hardening Guide
|
|
:date: 2023-03-15 09:55:25+00:00
|
|
:toc:
|
|
|
|
Last updated: 19.03.2023
|
|
|
|
== Introduction
|
|
This guide is the result of closely following Fortigate VPN SSL vulnerabilities
|
|
over the years, actual cases of compromised firewalls, operational manuals and
|
|
reports of multiple gangs (e.g. _Conti manuals_) and my experience with Fortigates
|
|
of 15+ years and counting. By implementing all/some of the measures below you
|
|
will make your SSL VPN on Fortigate substantially harder to break in and thus less
|
|
attractive to the attackers.
|
|
|
|
|
|
|
|
== Change the default SSL VPN port 10443/443 to anything else
|
|
This security by obscurity actually works. In most cases, the attackers do
|
|
not target specific companies, but are looking for low hanging fruit. And the
|
|
easiest way to do so is to scan for known ports/services. And both, 443 and 10443, are
|
|
well known Fortigate listening ports. It is even easier - just search
|
|
Shodan/Censys for "Fortigate" and currently Shodan has 185K results for port
|
|
10443, and Censys 317K. That was what happened with a large VPN
|
|
credentials leak 2 years ago
|
|
https://www.linkedin.com/pulse/50000-vpn-usernames-passwords-from-fortigates-around-we-slobodyanyuk/
|
|
- all of the affected Fortigates were listening on either 443 or 10443 ports.
|
|
|
|
The possible downside can be that VPN users connecting via WiFi in hotels/caffe
|
|
may have outgoing ports blocked except 443, but with cellular packages being so
|
|
cheap today, it is viable for them to use their phone as hotspot for VPN
|
|
connectionis and avoid using public WiFi altogether.
|
|
|
|
|
|
image::x-fortigate-ssl-vpn-change-port.png[]
|
|
|
|
On the CLI:
|
|
|
|
----
|
|
config vpn ssl settings
|
|
set port 13123
|
|
----
|
|
|
|
|
|
== Do not use local users for authentication, and if using - keep passwords elsewhere or/and enable MFA
|
|
In general, keeping all the security info in one box (Fortigate here) is a bad
|
|
practice. The mentioned vulnerability CVE-2018-13379 affected only Fortigates
|
|
with local VPN users having local authentication. Additionally, you give up
|
|
password policies, centralized system to expire/change passwords,
|
|
non-repeatability of the passwords etc. with such locally authenticated on the
|
|
Fortigate users. Integrating user authentication with existing user database
|
|
(LDAP/Active Directory/Cloud AD) is a breeze in Fortigate.
|
|
|
|
|
|
== Enable Multi-Factor Authentication for VPN users
|
|
ANY form of MFA will be better than none. Hardware Fortigate come with 2 mobile
|
|
application FortiTokens for free. Additionally, you can use SMS as MFA, but will
|
|
cost you money, or email that is completely free.
|
|
The email as MFA is not visible nor enabled by default, so I wrote a short guide
|
|
how to use it
|
|
https://yurisk.info/2020/03/01/fortigate-enable-e-mail-as-mfa-and-increase-token-validity-time/[enable e-mail as a two-factor authentication for a user and increase token timeout]
|
|
|
|
And of course, any 3rd party providing MFA can be used via RADIUS protocol
|
|
(Okta/Azure/Duo/etc.)
|
|
|
|
There is also option of _client_ PKI certificates as MFA, which is quite secure,
|
|
but also is most complex in setting up of all. Client certificates do not work
|
|
together with SAML authentication (Azure/etc.), which is also a disadvantage.
|
|
|
|
|
|
== Limit access to VPN SSL portal to specific IP addresses
|
|
|
|
If your users happen to have static IP addresses assigned by their ISP, it is an excellent way to
|
|
limit exposure of VPN SSL portal.
|
|
|
|
image::x-fortigate-vpn-ssl-allow-specific-ips.png[]
|
|
|
|
|
|
== Move VPN SSL listening interface to a Loopback interface
|
|
This step will give an additional security control - Security Rule.
|
|
The benefits of which are:
|
|
|
|
* The rule is highly visible, not hidden in CLI as Local-in Policy.
|
|
* It will have detailed traffic & security logs.
|
|
* It enables to turn SSL VPN access on and off on a time schedule.
|
|
* Allows us to disable SSL VPN access in one click (just disable this security
|
|
rule) without deleting anything.
|
|
* Makes possible to use ISDB address objects (See below on blocking Tor Exit
|
|
Nodes).
|
|
* And finally, as SSL VPN is NOT hardware-accelerated on any Fortigate, no matter where it
|
|
is set, on physical or Loopback interface, no reason to avoid Loopback here.
|
|
|
|
To set it up:
|
|
|
|
* Create a Loopback interface (here _Loop33_ with IP of _13.13.13.13_, not shown)
|
|
* Enable VPN SSL on this Loopback in VPN SSL Settings:
|
|
|
|
image::x-fortigate-ssl-vpn-loopback-vpn-setings.png[]
|
|
|
|
* Allow access to the Loopback on the listening port from the Internet. I use _all_ as a
|
|
source (rule id _2_)
|
|
here, but see other recommendations on limiting source IP for finer control:
|
|
|
|
|
|
image::x-fortigate-ssl-vpn-loopback-security-rule.png[]
|
|
|
|
== (Less preferred than above) Limit access to SSL VPN portal in Local-in Policy
|
|
The idea here is that unlike limits in the VPN SSL Settings, limits in the
|
|
Local-in Policy come before any traffic reaches VPN SSL daemon. Starting with
|
|
FortiOS 7.2 we can also use in Local-in Policies GeoIP objects, external feeds (I
|
|
haven't seen much benefit in them though). As I mentioned above, due to CLI-only
|
|
nature of the Local-in Policy, it is more manageable to use rather Loopback for
|
|
SSL VPN connections. But Local-in policy can do the job as well, see some
|
|
examples of using it here
|
|
https://yurisk.info/2022/07/04/fortigate-local-in-policy-configuration-examples-for-vpn-ipsec-vpn-ssl-bgp-and-more/[Fortigate Local-in policy configuration examples for VPN IPSec, VPN SSL, BGP and more] and https://yurisk.info/2020/06/07/fortigate-local-in-policy/[Fortigate Local in Policy what it does and how to change/configure it]
|
|
|
|
|
|
== Limit access to portal by GeoIP location
|
|
When your users are located in a specific country(s), it is advisable to at
|
|
least limit access to the VPN to those countries. E.g. for users coming from
|
|
Israel:
|
|
|
|
* Create an address of type _Geography_:
|
|
|
|
image::x-fortigate-ssl-vpn-geography.png[]
|
|
|
|
* Use it in VPN SSL Settings:
|
|
|
|
image::x-fortigate-ssl-vpn-geoip-vpn-settings.png[]
|
|
|
|
The option to use Geo objects appeared in newer FortiOS, so if you have an older
|
|
version, moving SSL VPN to loopback interface will give you this option.
|
|
|
|
|
|
== Block access to/from Tor Exit Nodes and Relays to anything
|
|
Attackers using Tor are pretty much untraceable, so this motivates them to
|
|
brute-force from Tor network a lot. Again, it is possible to implement only when your SSL VPN is listening on the Loopback
|
|
interface - neither VPN Settings, nor Local-in Policy accept ISDB addresses so
|
|
far. Just use the ISDB objects for Tor Exit Nodes and Relays, and VPN
|
|
Anonymizers in the
|
|
security rule that is above the VPN SSL rule to block them.
|
|
|
|
|
|
image::x-fortigate-ssl-vpn-tor-exit-nodes.png[]
|
|
|
|
Security Rule to block access from Tor to the Loopback interface where SSL VPN
|
|
is listening:
|
|
|
|
image::x-fortigate-ssl-vpn-block-tor-to-loopback.png[]
|
|
|
|
|
|
|
|
|
|
== Install trusted CA-issued certificate, but don't issue Let's Encrypt certificates directly on the Fortigate
|
|
|
|
Users, and people in general, are suspicious of anything strange/new/unknown. If
|
|
they get used to a valid TLS certificate from a trusted CA Authority on each
|
|
login into VPN SSL, they will immediately catch the browser error when being
|
|
exposed to Man-in-the-middle attack. Users are your friends, just teach them
|
|
good habits and they will be your allies.
|
|
|
|
_Let's encrypt_ certificates - yes, they are free and trusted. But, issuing them
|
|
directly on the Fortigate has 2 disadvantages:
|
|
|
|
. It enables _Acme_ protocol daemon to listen on port 80, and it HAS to be open
|
|
from ANY for auto-renewal to work, and exposing any additional daemon to the
|
|
Internet is a bad idea. To be exact - you need to have port 80 open only for the
|
|
period of issuing/renewing the certificate. So, you may, if you want to, enable
|
|
incoming port 80 from any when requesting certificate, then close the port until
|
|
time comes to renew it. But then it is no different from manually requesting and
|
|
importing.
|
|
. It does not support requesting _wildcard_ certificates, only a specific
|
|
subdomain one. And this has additional downside - your VPN subdomain gets logged
|
|
on the Internet for everyone to see. Just search here
|
|
https://crt.sh/?q=yurisk.com
|
|
|
|
|
|
I do use Let's Encrypt certificates, but on a separate
|
|
Linux server from which I export then import the certificates to the Fortigate
|
|
manually.
|
|
|
|
|
|
== Configure email alert on each successful VPN SSL connection
|
|
Why on successful and not failed? The real-life experience proves that
|
|
after _nth_ alert on failed login in a day, people stop looking at them
|
|
at all. And in my opinion, the successful log in is more important than the
|
|
failed one.
|
|
I am working on a collection of automation stitches that will include also this
|
|
email alert, follow me for updates on this.
|
|
|
|
|
|
== Prevent re-using the same user account to connect in parallel
|
|
|
|
You can, by default, connect with the same VPN user from different locations at
|
|
the same time. To somewhat improve on this, disable simultaneous logins for
|
|
users. This way, the connected user will be disconnected when someone else logs
|
|
in with his/her credentials - this would alert the user that something fishy is
|
|
going on. You set this feature per Portal.
|
|
|
|
image::x-fortigate-ssl-vpn-limit-logins-per-user.png[]
|
|
|
|
|
|
On CLI:
|
|
|
|
----
|
|
config vpn ssl web portal
|
|
edit "full-access"
|
|
set limit-user-logins enable
|
|
end
|
|
----
|
|
|
|
|
|
|
|
|
|
== In security rules, allow access only to specific destinations and services, not _all_
|
|
I see it many times - to save few clicks, admins put in the _Destination_ column
|
|
of the SSL VPN security rule _all_/whole LAN, instead of specific host(s) with
|
|
specific services. If attackers get hold of VPN connection to the Fortigate,
|
|
they will mass scan internal LAN for AD Domain Controllers, SMB shares,
|
|
enumerate all hosts and none of this will happen if you harden the VPN Remote
|
|
Access rules to specific services and hosts.
|
|
|
|
image::x-fortigate-ssl-rule-to-specific-services.png[]
|
|
|
|
|
|
== If not using VPN SSL, disable it, or assign to a dummy interface
|
|
The VPN SSL setting is *on* by default, which is ok - as long as there is no
|
|
listening interface assigned to it and no security rules using `ssl.root`
|
|
exist, the service will NOT listen actually. On some FortiOS versions you have
|
|
to do it on CLI. If you want to disable temporarily SSL VPN without deleting
|
|
anything, you could, besides clicking on _Disable_, assign it a Loopback
|
|
interface which you also put in a _Down_ state.
|
|
|
|
image::x-fortigate-ssl-vpn-assign-loopback-which-is-disabled.png[]
|
|
|
|
|
|
On CLI:
|
|
|
|
----
|
|
config vpn ssl settings
|
|
set status disable
|
|
set source-interface Loop1
|
|
end
|
|
----
|
|
|
|
|
|
== Create a no-access portal and set it as default in the VPN settings
|
|
Once you have VPN SSL enabled, you *have* to specify the default portal
|
|
to which all unmapped to portals users will be assigned. To prevent unintended
|
|
users/groups connecting via this default portal, create the one disabling all
|
|
the access inside it and then set it as the default.
|
|
|
|
* Create a portal with no factual access:
|
|
|
|
----
|
|
config vpn ssl web portal
|
|
edit DefaultNoAccess
|
|
set tunnel-mode disable
|
|
set web-mode disable
|
|
set ipv6-tunnel-mode disable
|
|
next
|
|
end
|
|
----
|
|
|
|
|
|
* Make it the default portal:
|
|
|
|
----
|
|
config vpn ssl setting
|
|
set default-portal DefaultNoAccess
|
|
end
|
|
----
|
|
|
|
IMPORTANT: Make sure you have the relevant users/groups mapped to other, working portals, before doing this.
|
|
|
|
|
|
|
|
|
|
|
|
== Block offending IP after _n_ failed attempts
|
|
This slows down brute-force and scanning attacks on VPN SSL. This feature is on
|
|
by default, but the block duration is just 60 seconds. You will want to
|
|
tune it to your environment and users. I usually set number of failed login
|
|
attempts to 3, then block the offender for 10 minutes. In many cases it was
|
|
enough for accidental attackers to give up and move to another target.
|
|
|
|
This can be configured in CLI:
|
|
|
|
----
|
|
config vpn ssl settings
|
|
set login-attempt-limit 3
|
|
set login-block-time 600
|
|
end
|
|
----
|
|
|
|
Here I block the IP for 10 minutes after 3 unsuccessful authentication attempts.
|
|
The maximum duration of blocking is 86400 seconds, or 24 hours.
|
|
|
|
|
|
|
|
|
|
== Disable weak and outdated TLS protocols for SSL VPN
|
|
Even with newer FortiOS versions VPN SSL by default supports TLS 1.1, and TLS
|
|
1.2 versions that are outdated and recommended against usage everywhere. You can
|
|
set SSL VPN to use only TLS 1.2 & 1.3 (on CLI only) with this command ( I
|
|
thought of recommending to leave just TLS 1.3, but Forticlient is currently having
|
|
problems with using it on Windows 10 & 11, so not for now):
|
|
|
|
----
|
|
config vpn ssl settings
|
|
set ssl-min-proto-ver tls1-2
|
|
end
|
|
----
|
|
|
|
And make sure it worked:
|
|
|
|
----
|
|
curl -v https://vpn.yurisk.com:13123 --tlsv1.1 -o /dev/null
|
|
|
|
|
|
|
|
* Connected to vpn.yurisk.com (52.58.153.81) port 13123 (#0)
|
|
* ALPN, offering h2
|
|
* ALPN, offering http/1.1
|
|
* successfully set certificate verify locations:
|
|
* CAfile: /etc/ssl/certs/ca-certificates.crt
|
|
CApath: /etc/ssl/certs
|
|
} [5 bytes data]
|
|
* TLSv1.1 (OUT), TLS handshake, Client hello (1):
|
|
} [140 bytes data]
|
|
* TLSv1.1 (IN), TLS alert, Server hello (2):
|
|
{ [2 bytes data]
|
|
* error:1409442E:SSL routines:ssl3_read_bytes:tlsv1 alert protocol version
|
|
* stopped the pause stream!
|
|
* Closing connection 0
|
|
curl: (35) error:1409442E:SSL routines:ssl3_read_bytes:tlsv1 alert protocol
|
|
version
|
|
----
|
|
|
|
|
|
NOTE: This will prevent older browsers/Forticlients from connecting, but we talk
|
|
about _very_ old versions, like Internet Explorer 11, or Chrome version 50
|
|
(current one is 110). So it should not be a problem.
|
|
|
|
|
|
|
|
== Consider switching from VPN SSL to VPN IPSec for clients
|
|
A bit drastic, but in all those years of VPN SSL vulnerabilities happening, I
|
|
remember of no single critical CVE for the IPSec daemon in Fortigate. Yes, it is more
|
|
involved in configuring it, but it may well be worth the effort. You use on the
|
|
client side the same Forticlient.
|
|
|
|
|
|
== Consider moving VPN SSL into its own VDOM
|
|
This is a measure against the worst case scenario - remotely executable 0-day
|
|
happens in the SSL VPN daemon, and attackers break into your Fortigate. In this
|
|
scenario the attackers will most probably create their own admin users for
|
|
persistence, set up VPN for remote access with rules permitting _Any_ to the
|
|
internal LAN, and if not trying to hide - will delete/remove your admin user to
|
|
block you access to the Fortigate. If this happens with the Fortigate that all
|
|
your DMZ/LAN/Storage/Backup networks are connected to, the game is over. But if
|
|
the same happens to the Internet-facing VDOM that has only SSL VPN configs and
|
|
rules, well, maximum they will have access to is anything you explicitly allowed
|
|
in rules between VDOMs. And if you implemented specific rules to allow specific
|
|
protocols to specific hosts, that would be not much of a gain to the attackers.
|
|
And all Fortigate models except the smallest ones, have hardware acceleration on
|
|
their inter-VDOM links, so perfomance-wise you lose nothing as well.
|
|
And price-wise, every Fortigate (even the smallest 40F) includes 10 VDOMs for free.
|
|
|
|
|
|
== Additional Resources to follow
|
|
* https://www.fortiguard.com/psirt Fortinet announcements on new vulnerabilities.
|
|
* https://yurisk.info/category/fortigate.html My blog's Fortigate category, has RSS feed
|
|
* https://t.me/fortichat Fortinet-related Telegram group with experts (Russian language)
|
|
* https://community.fortinet.com/ Fortinet Community Forum, a lot of Fortinet TAC folks hang out there.
|
|
* https://www.reddit.com/r/fortinet/ Well, Reddit is Reddit.
|