1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        Go 語言安全編程系列(一):CSRF 攻擊防護

        共 4385字,需瀏覽 9分鐘

         ·

        2020-10-16 17:54

        1、工作原理

        在 Go Web 編程中,我們可以基于第三方 gorilla/csrf 包避免 CSRF 攻擊,和 Laravel 框架一樣,這也是一個基于 HTTP 中間件避免 CSRF 攻擊的解決方案,其中包含的中間件名稱是 csrf.Protect。

        注:CSRF 全名是 Cross-Site Request Forgery,即跨站請求偽造,這是一種通過偽裝授權(quán)用戶的請求來攻擊授信網(wǎng)站的惡意漏洞。

        我們來看看 csrf.Protect 是如何工作的:

        當(dāng)我們在路由器上應(yīng)用這個中間件后,當(dāng)請求到來時,會通過 csrf.Token 函數(shù)生成一個令牌(Token)以便發(fā)送給 HTTP 響應(yīng)(可以是 HTML 表單也可以是 JSON 響應(yīng)),對于 HTML 表單視圖,可以向視圖模板傳遞一個注入令牌值的輔助函數(shù) csrf.TemplateField,然后我們就可以在客戶端通過?{{?.csrfField }} 將包含令牌值的隱藏字段發(fā)送給服務(wù)端,服務(wù)端通過驗證客戶端發(fā)送的令牌值和服務(wù)端保存的令牌值是否一致來驗證請求來自授信客戶端,從而達到避免 CSRF 攻擊的目的。

        gorilla/csrf 被設(shè)計為兼容當(dāng)前流行的開源組件和框架,比如 Gorilla 工具集、net/http 包、Goji、Gin、Echo 等。

        2、使用示例

        接下來,學(xué)院君來簡單演示下如何在實際項目中使用 gorilla/csrf 提供的 csrf.Protect 中間件。

        HTML 表單

        首先是 HTML 表單,csrf.Protect 中間件使用起來非常簡單,你只需要在啟動 Web 服務(wù)器時將其應(yīng)用到路由器上即可,然后在渲染表單視圖時傳遞帶有令牌信息的 csrf.TemplateField 函數(shù):

        package?main

        import?(
        ????"github.com/gorilla/csrf"
        ????"github.com/gorilla/mux"
        ????"html/template"
        ????"net/http"
        )

        func?main()?{
        ????//?初始化路由器
        ????r?:=?mux.NewRouter()
        ????//?注冊表單頁面路由(GET)
        ????r.HandleFunc("/signup",?ShowSignupForm)
        ????//?提交注冊表單路由(POST)
        ????//?如果請求字段不包含有效的?CSRF?令牌,則返回?403?響應(yīng)
        ????r.HandleFunc("/signup/post",?SubmitSignupForm).Methods("POST")

        ????//?應(yīng)用?csrf.Protect?中間件到路由器?r
        ????//?該函數(shù)第一個參數(shù)是?32?位長的認(rèn)證密鑰(任意字符做?MD5?元算即可),用于加密?CSRF?令牌
        ????//?本地開發(fā)基于?HTTP?協(xié)議,所以第二個參數(shù)通過?csrf.Secure(false)?進行標(biāo)識
        ????http.ListenAndServe(":8000",
        ????????csrf.Protect([]byte("251e79cd5d1a994c51fd316f7040f13d"),?csrf.Secure(false))(r))
        }

        //?注冊表單頁面處理器
        func?ShowSignupForm(w?http.ResponseWriter,?r?*http.Request)?{
        ????//?傳遞注入?CSRF?令牌的?csrf.TemplateField?函數(shù)到注冊頁面
        ????t?:=?template.Must(template.ParseFiles("signup.html"))
        ????t.Execute(w,?map[string]interface{}{
        ????????csrf.TemplateTag:?csrf.TemplateField(r),
        ????})
        ????//?我們還可以通過 csrf.Token(r)?直接獲取令牌并將其設(shè)置到請求頭:w.Header.Set("X-CSRF-Token", token)
        ????//?這在發(fā)送?JSON?響應(yīng)到客戶端或者前端?JavaScript?框架時很有用
        }

        //?提交注冊表單處理器
        func?SubmitSignupForm(w?http.ResponseWriter,?r?*http.Request)?{
        ????//?暫不做任何處理
        }

        然后我們在在同級目錄下新建 signup.html,通過 {{ .csrfField }} 渲染隱藏的令牌字段:


        <html?lang="en">
        <head>
        ????<meta?charset="UTF-8">
        ????<title>Signuptitle>
        head>
        <body>
        ????<form?action="/signup/post"?method="post">
        ????????{{?.csrfField?}}
        ????????<input?type="text"?name="name">
        ????????<input?type="password"?name="password">
        ????????<hr/>
        ????????<button?id="submit">Submitbutton>
        ????form>
        body>
        html>

        啟動 Web 服務(wù)器,在瀏覽器中訪問 http://127.0.0.1:8000/signup,就可以通過源代碼查看到隱藏的包含 CSRF 令牌的輸入框了:

        如果我們試圖刪除這個輸入框或者變更 CSRF 令牌的值,提交表單,就會返回 403 響應(yīng)了:

        錯誤信息是 CSRF 令牌值無效。

        JavaScript 應(yīng)用

        csrf.Protect 中間件還適用于前后端分離的應(yīng)用,此時后端數(shù)據(jù)以接口方式提供給前端,不再有視圖模板的渲染,設(shè)置中間件的方式不變,但是傳遞 CSRF 令牌給客戶端的方式要調(diào)整:

        package?main

        import?(
        ????"encoding/json"
        ????"github.com/gorilla/csrf"
        ????"github.com/gorilla/mux"
        ????"net/http"
        )

        type?User?struct?{
        ????Id?string?`json:"id"`
        ????Name?string?`json:"name"`
        ????Website?string?`json:"website"`
        }

        func?main()?{
        ????r?:=?mux.NewRouter()

        ????//?設(shè)置路由前綴
        ????api?:=?r.PathPrefix("/api").Subrouter()
        ????//?在子路由上應(yīng)用?csrf.Protect?中間件
        ????api.Use(csrf.Protect([]byte("251e79cd5d1a994c51fd316f7040f13d")))
        ????//?如果客戶端?JavaScript?應(yīng)用部署在其他域名,需要通過?csrf.TrustedOrigins?設(shè)置服務(wù)端信任的客戶端域名列表
        ????//?api.Use(csrf.Protect([]byte("251e79cd5d1a994c51fd316f7040f13d"),?csrf.TrustedOrigins([]string{"cli.domain.com"})))

        ????//?獲取用戶信息接口路由
        ????api.HandleFunc("/user/{id}",?GetUser).Methods("GET")

        ????http.ListenAndServe(":8000",?r)
        }

        func?GetUser(w?http.ResponseWriter,?r?*http.Request)?{
        ????//?從路由參數(shù)中讀取用戶?id,再從數(shù)據(jù)庫查詢對應(yīng)用戶信息
        ????//?這里我們簡單模擬下用戶數(shù)據(jù)進行測試即可
        ????id?:=?r.FormValue("id")
        ????user?:=?User{Id:?id,?Name:?"學(xué)院君",?Website:?"https://xueyuannjun.com"}

        ????//?獲取令牌值并將其設(shè)置到響應(yīng)頭
        ????//?這樣一來,咱們的?JSON?客戶端或者?JavaScript?框架就可以讀取響應(yīng)頭獲取?CSRF?令牌值
        ????//?然后在后續(xù)發(fā)送?POST?請求時就可以通過?X-CSRF-Token?請求頭中帶上這個?CSRF?令牌
        ????w.Header().Set("X-CSRF-Token",?csrf.Token(r))
        ????b,?err?:=?json.Marshal(user)
        ????if?err?!=?nil?{
        ????????http.Error(w,?err.Error(),?500)
        ????????return
        ????}
        ????w.Write(b)
        }

        我們啟動 Web 服務(wù)器,請求 /api/user/1 接口,就可以獲取如下響應(yīng)信息:

        這樣一來,我們就可以在客戶端讀取響應(yīng)頭中的 CSRF 令牌信息了,以 Axios 庫為例,客戶端可以這樣發(fā)送包含 CSRF 令牌的 POST 請求:

        //?你可以從響應(yīng)頭中讀取?CSRF?令牌,也可以將其存儲到單頁面應(yīng)用的某個全局標(biāo)簽里
        //?然后從這個標(biāo)簽中讀取 CSRF 令牌值,比如這里就是這么做的:
        let?csrfToken?=?document.getElementsByName("gorilla.csrf.Token")[0].value

        //?初始化?Axios?請求頭,包含域名、超時和?CSRF?令牌信息
        const?instance?=?axios.create({
        ??baseURL:?"https://domain.com/api/",
        ??timeout:?1000,
        ??headers:?{?"X-CSRF-Token":?csrfToken?}
        })

        //?這樣一來,后續(xù)發(fā)送的所有?HTTP?請求都會包含?CSRF?令牌
        try?{
        ??let?resp?=?await?instance.post(endpoint,?formData)
        ??//?處理響應(yīng)
        }?catch?(err)?{
        ??//?處理異常
        }

        關(guān)于 Go Web 編程中的 CSRF 攻擊防護我們就簡單介紹到這里,更多細節(jié),請參考 gorilla/csrf 項目官方文檔:https://github.com/gorilla/csrf。

        (全文完)


        推薦閱讀


        福利

        我為大家整理了一份從入門到進階的Go學(xué)習(xí)資料禮包(下圖只是部分),同時還包含學(xué)習(xí)建議:入門看什么,進階看什么。

        關(guān)注公眾號 「polarisxu」,回復(fù)?ebook?獲?。贿€可以回復(fù)「進群」,和數(shù)萬 Gopher 交流學(xué)習(xí)。


        瀏覽 60
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            啊啊啊慢点插 | 樱桃AV | 欧美性猛交XX | 天堂俺去俺来也WWW色光网 | 日本性爱一区二区三区 | 大鸡巴操逼视频 | 99精品视频在线观看 | 丰满美女牲生活免费视频 | 国产精品不卡一区二区红桃视频 | 十大尺度做爰未删减电影暗欲韩国 |