stateful firewall issues (Was Re: Think Simple!)

Giorgos Keramidas keramida at ceid.upatras.gr
Wed Aug 30 19:42:33 EEST 2006


On 2006-08-30 19:39, maria <zakinthinos at freemail.gr> wrote:
>Giorgos Keramidas wrote:
>> 5) φιλτράρεις τα πακέτα στο *OUTPUT* chain, με βάση το interface τους
>>   και το αν έχουν source 127.0.0.1.  Γιατί να μην κάνεις τότε όμως το
>>   ίδιο με το IP address του PPP interface σου στο `lo' interface, ή στο
>>   `internal LAN' interface, ή να μην κάνεις το ίδιο με το `internal
>>   LAN' IP address σου στο `lo' και στο PPP interface.
>>
>>   Όπως καταλαβαίνεις, αυτή η ιδέα *δεν* είναι τόσο καλή, γιατί
>>   δημιουργεί την ανάγκη για NxN κανόνες στο `hot path' του firewall
>>   ruleset σου, όπου `N' ο αριθμός από τα interfaces που έχεις.  Και
>>   κάθε φορά που προσθέτεις ένα interface ακόμα, θα πρέπει να θυμάσαι να
>>   προσθέσεις και (2*N + 1) κανόνες ακόμα[1].  Αλλη δουλειά δεν είχαμε,
>>   να καθόμαστε να μετράμε κανόνες τώρα :P
>
> 1) 'hot path' ειναι το INPUT-OUTPUT filtering ?

'hot path' είναι το κομμάτι από το ruleset που βρίσκεται πριν από το
state-checking στάδιο.

Από αυτό το κομμάτι θα περάσουν ανεξαιρέτως όλα τα πακέτα, είτε ανήκουν
σε μια υπάρχουσα σύνδεση είτε όχι.  Κάθε κανόνας του 'hot path' θα
εφαρμοστεί σε κάθε πακέτο και μόνο αν το πακέτο καταφέρει να περάσει από
όλες αυτές τις 'εξαιρετικές' περιπτώσεις που έχεις βάλει εκεί θα φτάσει
στο στάδιο που ελέγχεται αν υπάρχει κάποιο state entry που να ταιριάζει
με αυτό.

Αντίθετα, αν ελέγχεις πρώτα όλα τα state entries (κάτι που συνήθως έχει
βελτιστοποιηθεί με hash tables από IP address & port numbers), τα πακέτα
τα οποία ανήκουν σε κάποια υπάρχουσα σύνδεση θα περάσουν γρήγορα από το
firewall.

Δεν ξέρω πόσο συμφέρει αυτό αλλά έχω την εντύπωση ότι δίνει ένα σαφές
προβάδισμα στα πακέτα που ήδη είναι γνωστό ότι ανήκουν σε κάποια
σύνδεση, και ύστερα ελέγχει τα υπόλοιπα για πιθανόν χρήσιμα πράγματα.
Επίσης μειώνει σημαντικά τον αριθμό των κανόνων στο ruleset, αφού αντί
να έχεις rulesets της μορφής:

      block if condition[0] ...
      block if condition[1] ...
      block if condition[2] ...
      ...
      block if condition[k] ...        # where k >> 1
      pass  if known-state

Εχεις κάτι πανέμορφα απλό σαν:

      pass   if known-state
      pass   if outgoing-connection
      block

Είναι σίγουρο πως το να ελέγχεις το state-table για κάθε πακέτο μπορεί
να είναι λιγότερο αποδοτικό από το να μπλοκάρεις *κάποιες* περιπτώσεις
με το χέρι πριν φτάσεις στο state table.

Αυτό είναι το μοναδικό "κόστος" μιας λύσης που ελέγχει πρώτα το state
table και μετά τις 'εξαιρέσεις'.

Πρόσεξε ότι η ανάποδη λύση, που ελέγχει πρώτα τις 'εξαιρέσεις' και μετά
το state table, έχει ένα σωρό μειονεκτήματα.  Αυτά φαίνονται παρακάτω:

    - Σε γενικές γραμμές, είναι πολύ περισσότερα τα πακέτα που αποτελούν
      ``μέρος'' μιας σύνδεσης από τα πακέτα που εγκαθιστούν μια νέα
      σύνδεση.

      Για παράδειγμα, στο μηχάνημα που δουλεύω τώρα, με uptime λίγες
      ώρες μόνο, βλέπω με ``netstat -s'' τα εξής:

          tcp packets sent            = 72370
          tcp packets received        = 53315
          tcp connections established =   994

      Βλέπεις πόσο μικρότερος είναι ο αριθμός από packets που δεν είναι
      ήδη μέρος ενός connection (επειδή είναι νέα connection requests);

      Κράτα το αυτό...

    - Το μήκος της αλυσίδας των κανόνων μεγαλώνει δραματικά γρήγορα.
      Για να συμπεριλάβεις όλες τις 'εξαιρέσεις' πρέπει να φτιάξεις
      ruleset με δεκάδες ή ακόμα κι εκατοντάδες κανόνες.

    - Και πάλι δεν ξέρεις αν έχεις 'πιάσει' όλες τις πιθανές καταστάσεις
      οι οποίες είναι προβληματικές.

    - Το μεγάλο μήκος της αλυσίδας των κανόνων οδηγεί σε καθυστερήσεις
      για *ΟΛΑ* τα εισερχόμενα πακέτα, ακόμα κι αν αφορούν μια υπάρχουσα
      σύνδεση (βλ. παραπάνω γιατί αυτό είναι σημαντικό).

    - Πολύ συχνά η αλυσίδα καταλήγει να είναι εντελώς αδύνατον να
      συντηρηθεί, π.χ. από κάποιον άλλο (όχι απαραίτητα εσένα) ύστερα
      από 14 μήνες.

> 2) αν και αυτο με το 127.0.0.1 μαλλον θελει αλλαγη σε αυτο που
> προτεινες, στο ΝxΝ πως φτανεις ? (και μετα περνας στον αλλον τυπο που
> αναφερεις στο τελος)

Αν έχεις N network interfaces, πόσους κανόνες χρειάζεσαι για να ελέγξεις
ότι κανένα από αυτά δεν επιτρέπει invalid addresses; Η απάντηση
εξαρτάται από το συντακτικό του firewall ruleset, αλλά για IP Filter
είναι ``ακριβώς 2 + 2*Ν'', ένα νούμερο που είναι ``της τάξης του Ν''.

Για παράδειγμα, σε ένα τυπικό networked host, με ακριβώς μια κάρτα
δικτύου, υπάρχουν τουλάχιστον δύο interfaces:

    lo
    eth0

Και οι κανόνες για να εξασφαλίσεις ότι ούτε δέχεσαι, ούτε παίρνεις
πακέτα που δεν είναι σωστά για το IP address του κάθε interface είναι
(σε μορφή IP Filter ruleset):

    block in  all
    block out all

    pass in  quick on lo0  from 127.0.0.1/32 to 127.0.0.1/32
    pass out quick on lo0  from 127.0.0.1/32 to 127.0.0.1/32

    pass in  quick on eth0 from any          to a.b.c.d/32
    pass out quick on eth0 from a.b.c.d      to any

Ακριβώς 2 κανόνες για κάθε interface και 2 κανόνες που θέτουν το default
firewall policy = 2 + 2 * N.

Αν προστεθεί ένα νέο interface οι κανόνες είναι πλέον:

    block in  all
    block out all

    pass in  quick on lo0  from 127.0.0.1/32 to 127.0.0.1/32
    pass out quick on lo0  from 127.0.0.1/32 to 127.0.0.1/32

    pass in  quick on eth0 from any          to a.b.c.d/32
    pass out quick on eth0 from a.b.c.d/32   to any

    pass in  quick on eth1 from any          to x.y.z.w/32
    pass out quick on eth1 from x.y.z.w/32   to any

Πάλι οι κανόνες είναι ακριβώς 2 + 2 * N (όπου Ν πλέον 3).

Στη γενική περίπτωση ενός host με N interfaces λοιπόν, μόνο αυτή η
'εξαίρεση' προσθέτει (2 + 2 * N) κανόνες στο ruleset σου.  Κι όλα αυτά
ΠΡΙΝ ΚΑΝ φτάσεις στον έλεγχο του state table και για μία μόνο από τις
περιπτώσεις που μπορεί να χαρακτηρίσει κανείς 'προβληματικές'.

Σκέψου τώρα αν το firewall σου είναι και router/gateway μεταξύ δικτύων
στα οποία γίνεται address translation.

Πρόσθεσε στους παραπάνω κανόνες και τους κανόνες που ελέγχουν αν ένα
destination address μπορεί να είναι routable επειδή ανήκει σε κάποιο από
τα Ν δίκτυα... σε κάθε interface... σε τί αριθμό κανόνων καταλήγεις;

> >6) Εχεις ένα σωρό άχρηστους κανόνες στο INPUT chain, για να κάνουν
> >  explicitly 'DROP' συγκεκριμένες περιπτώσεις.  Αντί να κάθεσαι να
> >  ασχολείσαι με κάθε μία περίπτωση ξεχωριστά, άσε το default INPUT
> >  chain policy να τα μαζέψει όλα κάτω από την ίδια, πανέμορφη 'DROP'
> >  ομπρέλα.

> περα απο το confuzed 127.0.0.1 'i want to startx' τα λοιπα ειναι
> προσπαθειες να αντιμετωπιστουν INVALID πακετα πριν φθασουν να
> ελεγχθουν για state

Γιατί;

Ετσι μπορεί να κόψεις νωρίς "κάποια" invalid πακέτα, αλλά βάζεις ένα
ΤΕΡΑΣΤΙΟ ΚΑΙ ΑΧΡΗΣΤΟ overhead στα πακέτα που είναι ήδη μέρος μιας
σύνδεσης -- τα οποία όπως έγραψα παραπάνω είναι η συντριπτική πλειοψηφία
των πακέτων σε ένα workstation που δουλεύω εγώ τόσο καιρό.

> >8) Επιτρέπεις έτσι απλά και ανενδοίαστα όλα τα incoming connections για
> >  ports από 1024 και άνω.  ΑΥΤΟ ΔΕΝ ΕΙΝΑΙ ΚΑΛΗ ΙΔΕΑ!  Υπάρχουν περίπου
> >  64.510 διαφορετικοί λόγοι γιατί αυτό είναι βλακεία, αλλά θα σε αφήσω
> >  να τους ανακαλύψεις ξεχωριστά τον καθένα, καθώς θα στήνεις νέα
> >  services στο μηχάνημά σου.

> το ολο ζουμι της ιστοριας και η βασικη ερωτηση ειναι εδω
>
> ειναι προφανες οτι αφηνω πολλα ports ανοιχτα αλλα οι παρακατω γραμμες
> λενε (?)
>
> #αφησε τον χρηστη να κανει νεα connections
> #εχε το NEW εφόσον το POLICY ειναι DROP
>
> iptables -A OUTPUT -m conntrack --ctstate NEW,ESTABLISHED,RELATED -s
> $PPP_LOCAL -j ACCEPT
>
>
> #επετρεψε του να παραλαβει τα html data και
> #βαλε kai udp για να κανει resolve
>
> iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -p tcp -d $PPP_LOCAL --dport 1024: -j ACCEPT
> iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -p udp -d $PPP_LOCAL --dport 1024: -j ACCEPT

Ποια 'html data' λες ακριβώς;

Το HTTP πρωτόκολο δεν έχει ανάγκη από άλλο port πέρα από το outgoing:80.

> με αλλα λογια επιτρεπουμε να ερθουν πραγματα που εχει ξεκινησει ο
> ιδιος ο χρηστης και αφορουν δικες του συνδεσεις
>
> δεν τον περιοριζουμε ουτε με ποιον host θα επικοινωνησει ουτε σε τι
> port

Ετσι κι αλλιώς δεν περιορίζεσαι αν υπάρχει stateful firewall.

> ο περιορισμος που υιοθετουμε ειναι οτι με βαση το RELATED,ESTABLISHED,
> πρεπει το πακετο να ανηκει σε συνδεση που εχει ξεκινησει ο χρηστης
>
> τα bugs των iptables και ενας καλος tcp/ip programmer παιζουν ρολο
> εφ'οσον η μονη γραμμη αμυνας ειναι το tcp state και το σε ποια συνδεση
> ανηκει ενα πακετο

Δεν είμαι σίγουρος ότι ξέρω 100% τι κάνει το 'RELATED' αλλά για να το
λες, κάτι θα ξέρεις.

> >[1] Τα νέα interfaces είναι N+1, οπότε συνολικά θα πρέπει να προσθέσεις
> >   (N + 1)^2 - N^2 κανόνες = (N^2 + 2*N + 1) - N^2 = 2*N + 1.
>
> καταλαβα πως εφτασες στον τελικο τυπο αλλα δεν καταλαβα απο που
> βγαινει ο αρχικος (τα τετραγωνα)
>
> γενικα εδωσες περισσοτερη βαση στα normal errors (hosts, ports) και
> οχι στα states με τα οποια παιζουν οι κανονες (think declerative not
> imperative :)

Τα states είναι κάτι που αφορά τα πιο συχνά πακέτα, γι αυτό θα δεις ότι
μερικά firewalls δε σε ρωτάνε ΚΑΝ για το σημείο στο οποίο ελέγχονται τα
state table entries.  Για παράδειγμα, το IP Filter ακολουθεί το εξής
flow diagram για τα πακέτα:

    http://coombs.anu.edu.au/~avalon/ipfil-flow.html

Πρόσεξε πως το ``Packet State Check'' είναι πριν το ``Firewall Check''.

Με βάση τα παραπάνω, δεν αναρωτιέσαι ΓΙΑΤΙ είναι έτσι;




More information about the Linux-greek-users mailing list