I have no idea whether Mikrotik plans to address this somehow (maybe using an instance of http server dedicated solely for SCEP), but there is a workaround which allows to block other incoming HTTP traffic than the SCEP one (as restriction to particular source subnets and/or to particular (VPN) in-interfaces may not be sufficient) using the firewall.
The workaround is based on only allowing properly formatted SCEP requests to reach the web server, and relies on the layer7-protocol regexp matching.
When you add a CA certificate to the SCEP server, you have to set a path to it; to stay consistent with the example in the documentation, lets’s use path=/scep/test here. The whole layer7-protocol item then looks as follows:
/ip firewall layer7-protocol
add name=scep regexp=“^(GE|POS)T /scep/test\?operation=”
For more CAs, there would be more paths, so the regexp would have to permit all of them - e.g. if the other path would be /scep/other, the regexp covering both paths would be “^(GE|POS)T /scep/(test|other)\?operation=”
Now, I have no clue whether layer7-protocol matching should have ever worked in a different way, but as of the time of writing this, it needs a non-trivial firewall setup to work.
A typical firewall configuration is a stateful one, so it has action=accept connection=state=established,related as the very first rule in chains input and forward of /ip firewall filter, and the last rule in each of these chains is some kind of “drop the rest” one. In between these two, there are action=accept rules selectively accepting initial packets of new connections. If you place an action=accept layer7-protocol=scep protocol=tcp dst-port=80 rule among these, it will of course never match, because the first (SYN) packet of a TCP session doesn’t carry any payload yet, and if the first one is not accepted, no further one ever arrives because the Tik sends no response to the first one. So in order to ever get the packet carrying the actual HTTP request, which is the fourth one of the TCP session, you have to accept all incoming connections to TCP port 80 - chain=input action=accept protocol=tcp dst-port=80 tcp-flags=syn,!ack. Hence you then have to actively break those already accepted ones, which do not contain the proper SCEP request in their first payload-carrying packet, and you have to do that before the payload-carrying packet the actually reaches the server.
The tcp-flags=syn,!ack is there on purpose, so that the eventual attacker could not ignore the TCP RST received. The same behaviour can be achieved using /ip firewall connection tracking set loose-tcp-tracking=no, but this affects the whole firewall and it may not be desired.
So you need to place the rule matching on layer7-protocol=scep protocol=tcp dst-port=80 to chain=input of /ip firewall mangle, and set its action to mark-connection, assigning new-connection-mark=scep, and a rule breaking the “wrong” connections even before the chain=input action=accept connection=state=established,related one in /ip firewall filter. It will be chain=input action=reject reject-with=tcp-reset protocol=tcp connection-mark=**!**scep connection-bytes=180-500000 dst-port=80
So the complete firewall then looks as follows:
/ip firewall layer7-protocol
add name=scep regexp=“^(GE|POS)T /scep/test\?operation=”
/ip firewall filter
add action=reject chain=input connection-bytes=180-500000 connection-mark=!scep dst-port=80 protocol=tcp reject-with=tcp-reset
add action=accept chain=input connection-state=established,related,untracked
add action=drop chain=input connection-state=invalid
… some permissive rules unrelated to SCEP …
add action=accept chain=input dst-port=80 protocol=tcp tcp-flags=syn,!ack
… some permissive rules unrelated to SCEP …
add action=drop
/ip firewall mangle
… some rules unrelated to scep, must not shadow the scep-related one …
add action=mark-connection chain=input layer7-protocol=scep new-connection-mark=scep port=80 protocol=tcp
… some more rules unrelated to scep …
I can see two security risks here:
- some vulnerability of the SCEP server itself - cannot be helped by means of a firewall
- memory and/or CPU exhaustion due to processing of layer7 rules, which requires a lot of memory and CPU power per each connection - hence it makes sense to add other match conditions to the mangle rule to reduce the number of sources which can trigger the layer7 processing if the application case allows that