In meinem iptables-Skript habe ich versucht, so feinkörnige Regeln wie möglich zu schreiben. Ich beschränke mich darauf, welche Benutzer welche Dienste nutzen dürfen, teils aus Sicherheitsgründen, teils als Lernübung.
Verwenden von iptables v1.4.16.2 unter Debian 6.0.6 unter Ausführen des 3.6.2-Kernels.
Ich bin jedoch auf ein Problem gestoßen, das ich noch nicht ganz verstehe.
ausgehende Ports für alle Benutzer
Das funktioniert einwandfrei. Ich habe keine allgemeinen Statusverfolgungsregeln.
## Ausgehender Port 81 $ IPTABLES -A OUTPUT -p tcp --dport 81 -m conntrack --ctstate NEU, GEGRÜNDET -j AKZEPTIEREN $ IPTABLES -A INPUT -p tcp --sport 81 -s $ MYIP -m conntrack --ctstate ESTABLISHED -j ACCEPT
ausgehende Ports mit Benutzeranpassung
## ausgehender Port 80 für Benutzerkonto $ IPTABLES -A OUTPUT - Match-Besitzer - UID-Besitzer Benutzerkonto -p TCP --dport 80 -m Conntrack --ctstate NEU, GEGRÜNDET --sport 1024: 65535 -j AKZEPTIEREN $ IPTABLES -A INPUT -p tcp --sport 80 --dport 1024: 65535 -d $ MYIP -m conntrack --ctstate ESTABLISHED -j ACCEPT
Dadurch kann Port 80 nur für das Konto "Benutzerkonto" ausgegeben werden, aber Regeln wie diese für den TCP-Verkehr haben Probleme.
## Standardregeln für ausgehende Protokolle + Blockierungen $ IPTABLES -A OUTPUT -j LOG --log-Präfix "BAD OUTGOING" --log-ip-options --log-tcp-options --log-uid $ IPTABLES -A OUTPUT -j DROP
Die Angelegenheit
Das obige funktioniert, der Benutzer "Benutzerkonto" kann Dateien einwandfrei erhalten. Kein anderer Benutzer im System kann ausgehende Verbindungen zu Port 80 herstellen.
Benutzerkonto @ Host: $ wget http://cachefly.cachefly.net/10mb.test
Aber das obige Wget hinterlässt x7 abgelegte Einträge in meinem Syslog:
18. Oktober 02:00:35 xxxx Kernel: BAD OUTGOING IN = OUT = eth0 SRC = xx.xx.xx.xx DST = 205.234.175.175 LEN = 40 TOS = 0x00 PREC = 0x00 TTL = 64 ID = 12170 DF PROTO = TCP SPT = 37792 DPT = 80 SEQ = 164520678 ACK = 3997126942 WINDOW = 979 RES = 0x00 ACK URGP = 0
Ich bekomme diese Drops nicht für ähnliche Regeln mit UDP-Verkehr. Ich habe bereits Regeln festgelegt, die einschränken, welche Benutzer DNS-Anfragen stellen können.
Die verworfenen ausgehenden ACK-Pakete scheinen vom Root-Konto (URGP = 0) zu stammen, was ich nicht verstehe. Auch wenn ich das Benutzerkonto gegen root tausche.
Ich glaube, dass ACK-Pakete als neu eingestuft werden, da conntrack nach dem dritten Schritt des 3-Wege-Handshakes beginnt, Verbindungen zu verfolgen, aber warum werden die Pakete verworfen?
Können diese Tropfen ignoriert werden?
Bearbeiten
Daher sehe ich oft Regeln wie diese, die für mich gut funktionieren:
$ IPTABLES -A OUTPUT -s $ MYIP -p tcp -m tcp --dport 80 -m state --state NEW, ESTABLISHED -j ACCEPT $ IPTABLES -A INPUT -p tcp -m tcp --sport 80 -d $ MYIP -m state --state ESTABLISHED -j ACCEPT
Ich habe "-m state --state" gegen "-m conntrack --ctstate" getauscht, da die Statusübereinstimmung anscheinend veraltet ist.
Ist es eine bewährte Methode, allgemeine Regeln für die Statusverfolgung zu haben? Werden die oben genannten Regeln nicht als korrekt angesehen?
Wäre so etwas für eine strenge Kontrolle über ausgehende Benutzerverbindungen besser?
$ IPTABLES -A INPUT -m conntrack --ctstate ESTABLISHED -j ACCEPT $ IPTABLES -A OUTPUT -m conntrack --ctstate ESTABLISHED -j ACCEPT $ IPTABLES -A OUTPUT -p tcp --dport 80 -s $ SERVER_IP_TUNNEL -m conntrack --ctstate NEW -m Eigentümer --uid-Eigentümer Benutzerkonto -j AKZEPTIEREN $ IPTABLES -A OUTPUT -p tcp --dport 80 -s $ SERVER_IP_TUNNEL -m conntrack --ctstate NEW -m Eigentümer --uid-Eigentümer otheraccount -j ACCEPT
Antworten:
Um es kurz zu machen, diese ACK wurde gesendet, als die Steckdose niemandem gehörte. Anstatt Pakete zuzulassen, die sich auf einen Socket beziehen, der dem Benutzer gehört
x
, lassen Sie Pakete zu, die sich auf eine Verbindung beziehen, die von einem Socket vom Benutzer initiiert wurdex
.Die längere Geschichte.
Um das Problem zu verstehen, ist es hilfreich zu verstehen, wie
wget
und HTTP-Anforderungen im Allgemeinen funktionieren.Im
wget
stellt eine TCP-Verbindung zu hercachefly.cachefly.net
und sendet nach dem Herstellen eine Anfrage im HTTP-Protokoll, die besagt: "Bitte senden Sie mir den Inhalt von/10mb.test
(GET /10mb.test HTTP/1.1
). Übrigens, können Sie die Verbindung bitte nicht schließen, nachdem Sie fertig sind (Connection: Keep-alive
). Der Grund Dies liegt daran, dass der Server die Verbindung wiederverwenden kann, falls er mit einer Umleitung für eine URL mit derselben IP-Adresse antwortet.Jetzt kann der Server entweder antworten: "Hier kommen die von Ihnen angeforderten Daten, achten Sie darauf, dass sie 10 MB groß sind (
Content-Length: 10485760
), und ja, OK, ich lasse die Verbindung offen." Oder wenn die Größe der Daten nicht bekannt ist: "Hier sind die Daten. Leider kann ich die Verbindung nicht offen lassen, aber ich werde Ihnen mitteilen, wann Sie den Download der Daten beenden können, indem Sie mein Verbindungsende schließen."In der obigen URL sind wir im ersten Fall.
Sobald
wget
er die Header für die Antwort erhalten hat, weiß er, dass seine Arbeit erledigt ist, sobald er 10 MB Daten heruntergeladen hat.Grundsätzlich werden
wget
die Daten gelesen, bis 10 MB empfangen wurden, und beendet. Aber an diesem Punkt gibt es noch mehr zu tun. Was ist mit dem Server? Es wurde gesagt, die Verbindung offen zu lassen.wget
Schließt vor dem Beenden (close
Systemaufruf) den Dateideskriptor für den Socket. Anschließendclose
beendet das System die Bestätigung der vom Server gesendeten Daten und sendet eineFIN
Meldung: "Ich werde keine weiteren Daten senden". An diesem Punktclose
kehrt zurück und wird beendetwget
. Der TCP-Verbindung ist kein Socket mehr zugeordnet (mindestens keiner, der einem Benutzer gehört). Es ist jedoch noch nicht fertig. Nach dem EmpfangFIN
sieht der HTTP-Server das Dateiende, wenn er die nächste Anforderung vom Client liest. In HTTP bedeutet das "keine Anfrage mehr, ich werde mein Ende schließen". Also sendet es auch seine FIN, um zu sagen: "Ich werde auch nichts senden, diese Verbindung wird unterbrochen."Nach Erhalt dieser FIN sendet der Client eine "ACK". Aber zu diesem Zeitpunkt
wget
ist es längst vorbei, so dass ACK nicht von einem Benutzer stammt. Aus diesem Grund wird es von Ihrer Firewall blockiert. Da der Server die ACK nicht empfängt, wird die FIN immer wieder gesendet, bis sie aufgibt und Sie mehr abgelegte ACKs sehen. Das bedeutet auch, dass Sie durch das Löschen dieser ACKs für einige Zeit unnötig Ressourcen des Servers verwenden (der einen Socket im Status LAST-ACK halten muss).Das Verhalten wäre anders gewesen, wenn der Client nicht "Keep-Alive" angefordert hätte oder der Server nicht mit "Keep-Alive" geantwortet hätte.
Wie bereits erwähnt, möchten Sie bei Verwendung des Verbindungs-Trackers jedes Paket im Status ESTABLISHED und RELATED durchlassen und sich nur um
NEW
Pakete kümmern .Wenn Sie
NEW
Pakete vom Benutzer zulassen,x
aber keine Pakete vom Benutzery
, werden andere Pakete für vom Benutzer hergestellte Verbindungenx
durchlaufen, und weil vom Benutzer keine Verbindungen hergestellt werden könneny
(da wir dieNEW
Pakete blockieren , die die Verbindung herstellen würden). Es wird kein Paket für Benutzerverbindungeny
durchlaufen.quelle
- Nun, zumindest implizieren die Regeln, die Sie gezeigt haben, dies nicht.
Es gibt auch einen Raum für Ratschläge - überprüfen Sie die Benutzer nicht auf ESTABLISHED-Streams, sondern nur auf NEW. Ich sehe auch keinen Grund darin, den Quellport zu überprüfen, wenn ich Incoming ESTABLISHED überprüfe. Was ist der Unterschied, welcher Port es war? Es befindet sich bereits im Status ESTABLISHED gegenüber dem PoV von conntrack. Die Firewall sollte so einfach wie möglich, aber dennoch effizient sein, sodass der Rasiermesser- Ansatz von Occam am besten passt.
quelle