내 iptables 스크립트에서 나는 가능한 한 세분화된 규칙을 작성하려고 노력해 왔습니다. 부분적으로는 보안을 위해, 부분적으로는 학습 연습으로 어떤 사용자가 어떤 서비스를 사용할 수 있는지 제한합니다.
3.6.2 커널을 실행하는 Debian 6.0.6에서 iptables v1.4.16.2를 사용합니다.
그런데 도저히 이해할 수 없는 문제에 봉착했습니다...
모든 사용자를 위한 발신 포트
이것은 매우 잘 작동합니다. 일반적인 상태 추적 규칙이 없습니다.
## 나가는 포트 81 $IPTABLES -A 출력 -p tcp --dport 81 -m conntrack --ctstate 신규, 설정됨 -j 수락 $IPTABLES -A 입력 -p tcp --sport 81 -s $MYIP -m conntrack --ctstate 설립 -j 수락
나가는 포트 일치 사용자
## 사용자 계정의 나가는 포트 80 $IPTABLES -A 출력 --match owner --uid-owner useraccount -p tcp --dport 80 -m conntrack --ctstate 신규, 확립됨 --sport 1024:65535 -j accept $IPTABLES -A 입력 -p tcp --sport 80 --dport 1024:65535 -d $MYIP -m conntrack --ctstate 설립 -j 수락
이렇게 하면 "useraccount" 계정만 포트 80을 사용할 수 있지만 TCP 트래픽에 대한 이러한 규칙에는 문제가 있습니다.
## 기본 발신 로그 + 차단 규칙 $IPTABLES -A 출력 -j log --log-prefix "BAD OUTGOING" --log-ip-options --log-tcp-options --log-uid $IPTABLES -A 출력 -j 삭제
질문
위 작업이 작동하고 사용자 "useraccount"가 파일을 완벽하게 가져올 수 있습니다. 시스템의 다른 사용자는 포트 80으로 나가는 연결을 설정할 수 없습니다.
useraccount@host:$ wget http://cachefly.cachefly.net/10mb.test
그러나 위의 wget은 내 시스템 로그에 x7 삭제된 항목을 남겼습니다.
Oct 18 02:00:35 xxxx 커널: 나가는 오류 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
UDP 트래픽에 대한 유사한 규칙에 대해서는 이러한 삭제 메시지가 표시되지 않습니다. DNS 요청을 할 수 있는 사람을 제한하는 규칙을 설정했습니다.
삭제된 나가는 ACK 패킷은 루트 계정(URGP=0)에서 오는 것 같은데, 이해할 수 없습니다. 사용자 계정을 루트로 바꾸더라도.
conntrack이 3-way handshake의 3단계 이후에 연결 추적을 시작하기 때문에 ACK 패킷이 새 패킷으로 분류된다고 생각하는데 왜 삭제됩니까?
이러한 방울을 무시해도 안전합니까?
편집하다
그래서 나는 종종 나에게 잘 맞는 다음과 같은 규칙을 봅니다.
$IPTABLES -A 출력 -s $MYIP -p tcp -m tcp --dport 80 -m 상태 --신규, 확립됨 -j 수락 $IPTABLES -A 입력 -p tcp -m tcp --sport 80 -d $MYIP -m 상태 --상태 설정됨 -j 수락
상태 일치가 더 이상 사용되지 않기 때문에 "-m state --state"를 "-m conntrack --ctstate"로 대체했습니다.
보편적인 상태 추적 규칙을 갖는 것이 모범 사례입니까? 위의 규칙이 올바른 것으로 간주되지 않습니까?
나가는 사용자 연결을 엄격하게 제어하려면 이와 같은 것이 더 좋을까요?
$IPTABLES -A 입력 -m conntrack --ctstate 설정됨 -j 수락 $IPTABLES -A 출력 -m conntrack --ctstate 설정됨 -j 수락 $IPTABLES -A 출력 -p tcp --dport 80 -s $SERVER_IP_TUNNEL -m conntrack --ctstate NEW -m owner --uid-owner useraccount -j ACCEPT $IPTABLES -A 출력 -p tcp --dport 80 -s $SERVER_IP_TUNNEL -m conntrack --ctstate NEW -m owner --uid-owner otheraccount -j ACCEPT
답변1
간단히 말해서, 소켓이 누구에게도 속하지 않을 때 ACK가 전송됩니다. x
사용자의 소켓에 속하는 패킷을 허용하는 대신 사용자의 소켓에 의해 시작된 연결에 속하는 패킷을 허용합니다 x
.
이야기가 비교적 길어요.
이 문제를 이해하려면 wget
HTTP 요청이 일반적으로 작동하는 방식을 이해하는 것이 도움이 됩니다.
존재하다
wget http://cachefly.cachefly.net/10mb.test
wget
cachefly.cachefly.net
TCP 연결이 설정되면 " ()의 내용을 보내주십시오. 그런데 완료되면 연결()을 닫지 마십시오."라는 내용의 요청이 HTTP 프로토콜로 전송됩니다. 이렇게 하는 것은 서버가 동일한 IP 주소에서 URL 리디렉션으로 응답하면 연결을 재사용할 수 있기 때문입니다./10mb.test
GET /10mb.test HTTP/1.1
Connection: Keep-alive
이제 서버는 "요청한 데이터가 여기에 있습니다. 10MB 크기입니다( Content-Length: 10485760
). 예, 알겠습니다. 연결을 계속 유지하겠습니다"라고 응답할 수 있습니다. 또는 데이터의 크기를 모르는 경우 "여기 데이터가 있습니다. 죄송합니다. 연결을 계속 열어 둘 수는 없지만 연결 끝을 닫아 데이터 다운로드를 중지할 수 있는 시기를 알려 드리겠습니다."
위의 URL에서는 첫 번째 상황에 있습니다.
따라서 wget
응답 헤더를 얻으면 10MB의 데이터가 다운로드되면 작업이 완료되었음을 알 수 있습니다.
기본적으로 wget
10MB가 수신될 때까지 데이터를 읽고 종료하면 됩니다. 하지만 그때까지는 해야 할 일이 더 남아 있습니다. 서버는 어떻습니까? 연결을 열어두라는 지시를 받았습니다.
종료하기 전에 소켓의 파일 설명자를 wget
닫습니다( 시스템 호출). close
이 시점에서 close
시스템은 서버가 보낸 데이터에 대한 승인을 완료하고 FIN
"더 이상 데이터를 보내지 않겠습니다."라는 메시지를 보냅니다. 그런 다음 close
돌아가서 wget
종료하십시오. 더 이상 TCP 연결과 연관된 소켓이 없습니다(적어도 더 이상 어떤 사용자도 소유하지 않습니다). 그러나 아직 끝나지 않았습니다. 이 메시지를 받은 후 FIN
HTTP 서버는파일 끝클라이언트에서 다음 요청을 읽을 때. HTTP에서 이는 "더 이상 요청이 없습니다. 완료되었습니다"를 의미합니다. 그래서 "나도 아무것도 보내지 않고 연결이 끊어지고 있습니다"라는 FIN도 보냅니다.
FIN을 받은 후 클라이언트는 "ACK"를 보냅니다. 그러나 그 당시에는 wget
이미 사라진 지 오래였으므로 ACK는 어떤 사용자로부터도 전송되지 않았습니다. 그래서 방화벽으로 막혀있습니다. 서버는 ACK를 수신하지 않기 때문에 포기하고 더 많은 ACK가 삭제될 때까지 FIN을 계속해서 보냅니다. 이는 또한 이러한 ACK를 삭제하면 상당 기간 동안 서버 리소스를 불필요하게 사용하게 된다는 의미입니다(소켓이 LAST-ACK 상태로 유지되어야 함).
클라이언트가 "Keep-alive"를 요청하지 않거나 서버가 "Keep-alive"로 응답하지 않으면 동작이 달라집니다.
이미 언급했듯이 연결 추적기를 사용하는 경우 모든 패킷이 ESTABLISHED 및 RELATED 상태로 통과되도록 하고 패킷에 대해서만 걱정하면 됩니다 NEW
.
NEW
user 의 패킷은 허용 x
하지만 user 의 패킷은 허용하지 않는 경우 y
사용자가 설정한 연결의 다른 패킷은 x
통과하고 사용자가 연결을 설정할 수 없으므로 ( 연결을 설정하는 패킷을 y
차단했기 때문에 ) 모든 사용자 연결 패킷은 통과 하지 않습니다. .NEW
y
답변2
이렇게 하면 "useraccount" 계정만 포트 80을 사용할 수 있습니다.
- 글쎄요, 적어도 당신이 보여준 규칙은 실제로 그런 의미는 아닙니다.
한 가지 더 제안합니다. 설정된 스트림에 대해 사용자 확인을 수행하지 말고 새 확인만 수행하세요. 또한 들어오는 ESTABLISHED를 확인할 때 소스 포트를 확인하는 요점이 표시되지 않습니다. 차이점이 무엇인지, conntrack의 PoV에서 이미 ESTABLISHED 상태에 있습니다. 방화벽은 최대한 단순하면서도 효율적이어야 합니다.오캄의 면도날방법이 가장 적절합니다.