- XSS və CSRF hücumlarını izah etmək və onların qarşısını
textContent, ekranlaşdırma, CSP,SameSitekukiləri və CSRF tokenləri ilə almaq - Verilənləri serverdə icazə siyahıları ilə yoxlamaq, sirləri müştəri kodundan və Git-dən kənarda saxlamaq
- ESLint və Prettier-i qurmaq və layihəni tədricən TypeScript-ə keçirmək
Saytında şərh xanası var. Kimsə şərh kimi <img src=x onerror="stealCookies()"> yazır. Kodun şərhləri innerHTML ilə əlavə edirsə, bu skript hər ziyarətçinin brauzerində, onun sessiyası ilə işləyəcək. Veb üçün ən ciddi riskləri sadalayan OWASP Top 10 siyahısında inyeksiya (injection) hücumları var və XSS də onlara daxildir. Təhlükəsizlik sonda əlavə olunan funksiya deyil — gündəlik vərdişlər toplusudur.
XSS: saytlararası skript
XSS o zaman baş verir ki, etibarsız verilən səhifəyə HTML kimi daxil edilir və hücumçunun skripti sənin saytının adından işləyir: kukiləri oğurlayır, istifadəçinin adından əməliyyat edir. Müdafiə: istifadəçi mətnini textContent ilə yaz; HTML həqiqətən lazımdırsa, onu DOMPurify kimi kitabxana ilə təmizlə; React {value}-nu özü ekranlaşdırır (dangerouslySetInnerHTML istisna olmaqla); Content-Security-Policy başlığı skriptlərin haradan yüklənə biləcəyini məhdudlaşdırır.
const comment = '<img src="x" onerror="stealCookies()">';
// dangerous: the text is parsed as HTML and onerror runs
list.innerHTML += `<li>${comment}</li>`;
// safe: the text stays text
const item = document.createElement('li');
item.textContent = comment;
list.append(item);<img ...> mətnini görür, heç nə icra olunmur.HTML sətri qurmaq məcburiyyətindəsənsə (məsələn, serverdə şablon), xüsusi simvolları ekranlaşdır: < işarəsi <, & isə & olur və brauzer onları teq kimi yox, mətn kimi göstərir.
function escapeHtml(text) {
const map = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' };
return String(text).replace(/[&<>"']/g, (char) => map[char]);
}
console.log(escapeHtml('<img src=x onerror="stealCookies()">'));
console.log(escapeHtml('Tom & Jerry say "hi"'));▸ Gözlənilən nəticə
<img src=x onerror="stealCookies()"> Tom & Jerry say "hi"
CSRF: saytlararası sorğu saxtakarlığı
İstifadəçi bankın saytına daxil olub, sessiya kukisi brauzerdədir. Sonra o, başqa saytı açır və həmin səhifə gizli formanı bankın /transfer ünvanına göndərir. Brauzer kukini sorğuya avtomatik əlavə edir, bank isə elə bilir ki, əməliyyatı istifadəçi özü edib. Müdafiə: SameSite atributlu kukilər (Chrome bu atributu olmayan kukiləri Lax kimi qəbul edir), formadakı gizli təsadüfi CSRF tokeni (hücumçunun saytı onu oxuya bilmir), Origin başlığının yoxlanması və verilənləri heç vaxt GET sorğusu ilə dəyişməmək.
Set-Cookie: session=8f3a2c91; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=3600| Atribut | Nədən qoruyur |
|---|---|
HttpOnly | JavaScript kukini oxuya bilmir — XSS sessiyanı oğurlaya bilmir |
Secure | kuki yalnız HTTPS ilə göndərilir |
SameSite=Lax | başqa saytdan gələn POST sorğularına kuki qoşulmur — CSRF xeyli çətinləşir |
Max-Age | sessiyanın ömrünü məhdudlaşdırır |
Verilənləri yoxla, sirləri qoru
Müştəriyə etibar etmə: brauzerdən gələn hər şey — formalar, URL, başlıqlar, JSON — saxtalaşdırıla bilər; hücumçu sənin interfeysini ötüb API-yə birbaşa sorğu göndərir. Ona görə verilənləri serverdə yoxla: tip, uzunluq, format və icazə verilən qiymətlər (qadağan siyahısı yox, icazə siyahısı). Brauzerdəki yoxlama yalnız istifadəçinin rahatlığı üçündür. SQL sorğularını sətirləri birləşdirərək qurma — parametrli sorğular işlət. Böyük layihələrdə sxem kitabxanaları (məsələn, zod) kömək edir.
function validateOrder(input) {
const errors = [];
const allowedSizes = ['S', 'M', 'L'];
if (typeof input.email !== 'string' || !/^[^\s@]+@[^\s@]+\.[a-z]{2,}$/i.test(input.email)) {
errors.push('email: invalid format');
}
if (!Number.isInteger(input.quantity) || input.quantity < 1 || input.quantity > 10) {
errors.push('quantity: must be an integer 1-10');
}
if (!allowedSizes.includes(input.size)) {
errors.push(`size: must be one of ${allowedSizes.join(', ')}`);
}
return errors.length ? { ok: false, errors } : { ok: true };
}
console.log(validateOrder({ email: 'leyla@mail.az', quantity: 2, size: 'M' }));
console.log(validateOrder({ email: 'not-an-email', quantity: '100', size: 'XXL' }));▸ Gözlənilən nəticə
{ ok: true }
{ ok: false, errors: [ 'email: invalid format', 'quantity: must be an integer 1-10', 'size: must be one of S, M, L' ] }'100' sətirdir, ona görə Number.isInteger onu rədd edir — tip də yoxlanmalıdır. Bütün xətaları bir dəfədə qaytarmaq istifadəçiyə formanı tez düzəltməyə kömək edir.Sirlər (API açarları, parollar, tokenlər) brauzer koduna düşən kimi açıq olur — istənilən istifadəçi DevTools-da onları görür. Pullu API-yə sorğunu sənin serverin göndərməlidir, brauzer isə yalnız sənin serverinlə danışır. Sirləri .env faylında saxla və faylı .gitignore-a əlavə et. Vite-də VITE_ prefiksli dəyişənlər müştəri koduna daxil edilir — deməli, onlar ictimaidir.
Kod keyfiyyəti: ESLint, Prettier, TypeScript
ESLint kodu işə salmadan səhvləri və pis şablonları tapır: istifadə olunmayan dəyişənlər, ==, elan olunmamış adlar. Prettier kodu avtomatik formatlayır, ona görə komanda üslub haqqında mübahisə etmir. Hər ikisini redaktorda faylı saxlayanda və CI-də işə sal. Layihəyə ESLint əlavə etmək üçün npm init @eslint/config@latest, Prettier üçün npm install -D prettier kifayətdir.
// eslint.config.js
import js from '@eslint/js';
import globals from 'globals';
export default [
js.configs.recommended,
{
languageOptions: { globals: globals.browser },
rules: {
eqeqeq: 'error',
'no-unused-vars': 'warn',
'no-console': ['warn', { allow: ['warn', 'error'] }],
},
},
];npx eslint . bütün layihəni yoxlayır.const user={name:"Aysel",age:15,city:'Baku'}
function greet(u){return "Hi, "+u.name}
if(user.age>=14){console.log(greet(user))}npx prettier --write --single-quote . əmrindən sonra o, aşağıdakı bloka bənzəyəcək.const user = { name: 'Aysel', age: 15, city: 'Baku' };
function greet(u) {
return 'Hi, ' + u.name;
}
if (user.age >= 14) {
console.log(greet(user));
}TypeScript JavaScript-ə statik tiplər əlavə edir: səhvlər kod işə düşməzdən əvvəl, redaktorda görünür. Böyük layihəni bir günə köçürmək lazım deyil — keçid tədricən aparılır:
- 1tsconfig.json əlavə et
allowJsvəcheckJsseçimləri ilə — TypeScript mövcud JS fayllarını da yoxlamağa başlayır. - 2JSDoc tipləri yaz
/** @param {number} price */kimi şərhlər faylın adını dəyişmədən tip verir. - 3Faylları bir-bir
.ts-ə çevirƏn sadə, asılılığı az olan modullardan başla.
- 4
strictrejimini açSonda
"strict": trueən çox səhvi tutur, məsələn,nullola biləcək qiymətləri.
// shop.ts
interface Product {
id: number;
title: string;
price: number;
}
function total(products: Product[]): number {
return products.reduce((sum, p) => sum + p.price, 0);
}
total([{ id: 1, title: 'Pen', price: '2' }]);
total([{ id: 2, title: 'Notebook' }]);shop.ts(12,31): error TS2322: Type 'string' is not assignable to type 'number'.
shop.ts(13,8): error TS2741: Property 'price' is missing in type '{ id: number; title: string; }' but required in type 'Product'.npx tsc --noEmit icra olunanda: iki səhv kod heç işə düşmədən tapıldı. JavaScript-də '2' səssizcə sətir birləşməsinə, olmayan price isə NaN-a gətirib çıxarardı.escapeHtml(text) funksiyasını yaz: &, <, >, " və ' simvollarını uyğun olaraq &, <, >, " və ' ilə əvəz etsin. Bir replace və qiymətlər xəritəsi kifayətdir.
function escapeHtml(text) {
// replace & < > " ' with HTML entities
}
const comments = ['<b>Hello</b>', 'Tom & Jerry', '<img src=x onerror="steal()">'];
for (const comment of comments) {
console.log(escapeHtml(comment));
}▸ Gözlənilən nəticə
<b>Hello</b> Tom & Jerry <img src=x onerror="steal()">
Açıq yönləndirmənin qarşısını al: isSafeRedirect(target) yalnız iki halda true qaytarsın — tək / ilə başlayan və ardınca ikinci / və ya \ gəlməyən nisbi yol, yaxud host adı düz app.example.com olan https:// ünvanı.
function isSafeRedirect(target) {
// 1) relative path: /^\/(?![\/\\])/
// 2) otherwise parse with new URL() inside try...catch
return true;
}
const targets = [
'/lessons/42',
'//evil.example/login',
'/\\evil.example',
'https://app.example.com/profile',
'https://app.example.com.evil.example/',
'javascript:stealCookies()',
];
for (const target of targets) {
console.log(`${target} -> ${isSafeRedirect(target)}`);
}▸ Gözlənilən nəticə
/lessons/42 -> true //evil.example/login -> false /\evil.example -> false https://app.example.com/profile -> true https://app.example.com.evil.example/ -> false javascript:stealCookies() -> false
Əsas fikirlər
- XSS: istifadəçi verilənlərini heç vaxt HTML kimi daxil etmə —
textContent, ekranlaşdırma və ya təmizləmə işlət,Content-Security-Policyəlavə et. - CSRF: kukilər avtomatik göndərilir;
SameSite, CSRF tokenləri,Originyoxlaması və GET ilə dəyişiklik etməmək qoruyur. - Müştəriyə etibar etmə: verilənləri serverdə icazə siyahısı ilə yoxla, SQL üçün parametrli sorğular işlət.
- Sirlər yalnız serverdə və
.gitignore-dakı.env-də olur; sızan açarı dərhal ləğv et. - ESLint səhvləri tapır, Prettier formatlayır, TypeScript tip səhvlərini işə salmadan tutur — ona
checkJsilə tədricən keç.
Özünü yoxla
10 sual. Hər düzgün cavab XP qazandırır.