iT邦幫忙

2024 iThome 鐵人賽

DAY 26
1
IT 管理

30天從版控到code review的實踐指南系列 第 26

Day 26. Code Review 安全性原則:CSRF、其他篇

  • 分享至 

  • xImage
  •  

避免 Cross Site Request Forgery(CSRF)


CSRF 是一種網絡攻擊,攻擊者會在使用者已經登入的情況下,執行未授權的操作。攻擊者利用已驗證的 Session (Authenticated Session),即使用者已經透過登入等方式被確認其身份,Server 會讓這個 Session 維持被認證的狀態。攻擊者發送偽造的請求到受害者已經登入的網站,從而在使用者不知情的情況下進行惡意操作,例如修改帳戶資料、轉移資金等。

避免 CSRF 方法:

  1. 使用 CSRF Token:CSRF Token 是一個隨機產生的唯一識別碼,當使用者提交表單或進行請求時,Server 會將該 Token 加到請求中。這個 Token 通常與使用者的 Session 綁定,且只能用一次,從而確保請求來自已驗證的使用者。
  2. 使用 SameSite Cookie:SameSite Cookie 是一種防止瀏覽器在跨站點請求(Cross-Site Request)中自動發送 Cookie 的策略。瀏覽器在請求發送時只會攜帶符合 SameSite 規則的 Cookie。可將 SameSite 屬性設置為 Strict 或 Lax,避免 Cross-Site Request 攜帶敏感的 Cookie。
    • SameSite Cookie 的屬性:
      • Strict:只有當請求來自同一個網站(SameSite)時,瀏覽器才會攜帶 Cookie。這意味著 Cross-Site Request 不會攜帶該 Cookie,因此能夠有效防止 CSRF 攻擊。這是最嚴格的模式,但有時可能會限制安全的 Cross-Site 操作。

      • Lax:允許一些 Cross-Site Request 攜帶 Cookie,但僅限於安全的情況下(如使用 GET 請求進行的網頁訪問)。這個模式在大多數情況下能夠防止 CSRF 攻擊,同時不會破壞使用者的正常操作體驗。

      • None:Cookie 將在所有情況下都被發送,包括跨站請求。但需要確保 Cookie 是安全的(使用 HTTPS),否則瀏覽器會拒絕。

        範例:在 ASP Dotnet Core 將 SameSite 屬性設置為 None。


        • Startup.cs
        public void ConfigureServices(IServiceCollection services)
        {
            services.ConfigureApplicationCookie(options =>
            {
                options.Cookie.SameSite = SameSiteMode.None; // 將 SameSite 屬性設為 None
                options.Cookie.SecurePolicy = CookieSecurePolicy.Always; // 建議在 SameSite = None 時使用 Secure Cookie
            });
        }
        
        • 在 Controller 加 Cookie
        public class MyController : Controller
        {
            public IActionResult SetCookie()
            {
                var cookieOptions = new CookieOptions
                {
                    Expires = DateTimeOffset.UtcNow.AddDays(7), // 設 Cookie 過期時間
                    HttpOnly = true, // 防止 JavaScript 訪問
                    SameSite = SameSiteMode.None, // 將 SameSite 屬性設置為 None
                    Secure = true // 僅在 HTTPS 中傳輸 Cookie
                };
        
                Response.Cookies.Append("MyCookie", "cookieValue", cookieOptions);
                return Ok("Cookie has been set.");
            }
        }
        

避免使用不安全的函數


  1. 避免使用可能不安全的 API,如 eval()、setTimeout() 和 setInterval(),特別是在處理來自使用者的輸入時。

  2. 使用 Function 建構子(Constructor Function)或帶有任意 JavaScript 程式碼的 Function 調用都應謹慎,因為這些方法可能被利用執行惡意代碼。

    範例:

    // 不安全寫法
    var globalVar = "I am a global variable";
    
    var func = new Function('console.log(globalVar);'); // 沒有訪問到 globalVar
    func(); // 會報錯:ReferenceError: globalVar is not defined
    
    // 改善寫法 1:將 globalVar 作為參數傳遞
    var globalVar = "I am a global variable";
    var func = new Function('globalVar', 'console.log(globalVar);');
    func(globalVar); // 輸出:I am a global variable
    
    // 改善寫法 2:使用箭頭函數
    var globalVar = "I am a global variable";
    const func = () => {
        console.log(globalVar); // 輸出:I am a global variable
    };
    func();
    

避免開發過程中的全域變數


JavaScript 是單一執行緒的語言,污染全域命名空間可能導致競爭條件(Race Condition)和其他安全問題,應該盡量避免將變數設為全域性,使用模組化的方式來封裝變數和邏輯。

範例:Race Condition 通常都出現在非同步操作。

不好的寫法:setTimeout() 是非同步執行,兩個 incrementCounter() 可能幾乎同時讀取 counter 的值,然後都試圖更新它,將導致最後的 counter 值不正確。


let counter = 0;

function incrementCounter() {
    const temp = counter;
    setTimeout(() => {
        counter = temp + 1;
        console.log(`Counter: ${counter}`);
    }, Math.random() * 1000);
}

// 同時執行兩個遞增操作
incrementCounter();
incrementCounter();

改善寫法 1:使用 Promise。


let counter = 0;

function incrementCounter() {
    return new Promise((resolve) => {
        const temp = counter;
        setTimeout(() => {
            counter = temp + 1;
            console.log(`Counter: ${counter}`);
            resolve();
        }, Math.random() * 1000);
    });
}

Promise.all([incrementCounter(), incrementCounter()]);

改善寫法 2:使用 async/await。


let counter = 0;

function incrementCounter() {
    return new Promise((resolve) => {
        const temp = counter;
        setTimeout(() => {
            counter = temp + 1;
            console.log(`Counter: ${counter}`);
            resolve();
        }, Math.random() * 1000);
    });
}

async function run() {
    await incrementCounter();
    await incrementCounter();
}

run();

檢查依賴程式庫的安全性


  1. 定期檢查所使用的第三方程式庫和框架是否有已知的安全漏洞,使用工具如 npm 的 audit 或 yarn audit 來分析。
  2. 避免從不受信任的來源引入第三方 Script,始終確保第三方程式庫來源可靠。

使用 HTTPS


確保所有的 API 請求以及靜態資源均使用 HTTPS,防止被攻擊風險。

強制加密與解密機制


確保任何敏感數據的傳輸和存儲都經過加密,並避免將敏感數據(如密碼)直接存儲在 Client 端,如 LocalStorage、SessionStorage。

Summary ****


Code Review 檢查清單如下:

  1. 輸入和輸出編碼(Input and Output Encoding):檢查所有來自用戶的輸入是否進行了適當的編碼。
  2. 依賴項安全性(Dependency Security):檢查是否有過時的依賴或已知漏洞。
  3. API 調用(API call):審核 API 調用時,確保沒有暴露敏感資料。
  4. 錯誤處理:確保有適當的錯誤處理機制,避免將詳細錯誤訊息暴露給使用者。
  5. 權限控管:檢查是否正確實施了角色和權限控管,防止未經授權的操作。

這兩天說明了一些 JavaScript 程式碼撰寫與 Code Review 時應該注意的安全性建議,能幫助提升應用的安全性,減少漏洞風險。


上一篇
Day 25. Code Review 安全性原則:XSS 篇
下一篇
Day 27. Code Review 模組化與重用性-規則篇。
系列文
30天從版控到code review的實踐指南30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言