POZOR! Článek jsem napsal před více jak rokem, a tudíž už nemusí reflektovat můj nynější názor nebo může být zastaralý.
API je část aplikace, která si víc než jiná zaslouží větší pozornost na zabezpečení. V tomhle malém článku uvedu 5 tipů, které možná už znáte, ale možná taky ne a i kdyby, tak proč si je nepřipomenout :)
1. Používejte SSL
Dnes už je skoro samozřejmostí, že celé weby jsou pod HTTPS a pro API je to bezpodmínečně nutné. Koukněte jestli máte správně nastavená přesměrování z nezabezpečeného HTTP.
2. Povolte pouze ty HTTP hlavičky, která chcete
Prvně upozorním, že respektování CORS HTTP hlaviček je záležitost prohlížeče. Pokud použijete například cUrl v konzoli, tak lze podstrčit jakoukoli hlavičku s vlastním obsahem. Proto se nejedná o absolutní ochranu.
Nicméně i tak je pro prohlížeč dobré uvést hlavičky, které umožňujete přijmout. Stačí uvádět pouze ty hlavičky, které nespadají mezi ty základní (Accept, Accept-Language, Content-Language, Content-Type). To se hodí pro hlavičku ve které posíláte autorizační token.
header("Access-Control-Allow-Headers: Authorization");
3. Povolte pouze ty URL, které mohou k API přistupovat
Zde platí to samé jako pro bod 2. I zde má ale smysl povolit pouze tu URL, kterou pro kterou API provozujete, aby vaše API nebylo zneužité parazitující stránkou.
header("Access-Control-Allow-Origin: https://vasweb.cz");
Pokud API provozujete pro více než jeden web, je nutné už více řádků:
$httpOrigin = $_SERVER['HTTP_ORIGIN'];
if ($httpOrigin == "https://vasweb.cz" || $httpOrigin == "https://jinyvasweb.cz") {
header("Access-Control-Allow-Origin: " . $httpOrigin);
}
4. Komunikujte s API pomocí tokenu s časovou platností
Už jsem párkrát viděl API, které měla token u něhož se nijak neověřovalo, jestli není třeba 2 roky starý. Proč je to důležité? Může se stát, že dojde k jeho krádeži a je jedno, jestli ho ukládáte do cookies, localStorage nebo sessionStorage. Pokud se token nemění a nemá časovou platnost, je pro zloděje stálou možností, jak se pro API autorizovat.
Osobně mi vyhovuje standard JWT, kde do jednoho tokenu uložíte informace o ID uživateli (například, ale nesmí jít o citlivá data, protože jsou pouze zakódována v base64), časovou platnost a celé to podepíšete vlastním tajným klíčem. Takže pokud ho někdo nezná, můžete si být jistí tím, co je obsahem tokenu.
Například pomocí knihovny Firebase/JWT:
define("JWT_SERCRET", "takný klíč");
$data = [
"userId": 12,
"exp": 1356999524 // Čas expirace
];
$jwt = \Firebase\JWT\JWT::encode($id, JWT_SERCRET, 'HS512');
// $jwt = "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEyLCJleHAiOjEzNTY5OTk1MjR9.ZT70Ok3YZn3osdnM6uGvgzDTWS1Mknvj2EJb7Ar7jFwkSqpKrqSK3Lrz3MzxaWWvSczX-TugYwH4FGWYG9EzOQ"
$data = \Firebase\JWT\JWT::decode($jwt, JWT_SERCRET, ['HS512']);
5. Validujte a sanitizujte vstupní data
Nikdy nevěřte lidem, kteří používají vaše API.
Každý vstup (i když ho validujete už v JavaScriptu) je nutný zvalidovat (říct si, jestli odpovídá očekávanému formátu) a sanitizovat (odstranit od nechtěných symbolů).
$email = "jaroslav(.)@le/xa.com";
if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
echo "Adresa je validní";
} else {
echo "Adresa není validní";
}
$email = "jaroslav(.)@le/xa.com";
$email = filter_var($email, FILTER_SANITIZE_EMAIL);
echo $email; // jaroslav.@lexa.com
Užitečné odkazy
https://developer.mozilla.org/en-US/docs/Web/HTTP/Server-Side_Access_Control
https://dzone.com/refcardz/rest-api-security-1
https://www.owasp.org/index.php/REST_Security_Cheat_Sheet
http://php.net/manual/en/filter.filters.validate.php
http://php.net/manual/en/filter.filters.sanitize.php
Znáte někoho, komu by článek mohl pomoct? Zasdílejte mu ho :)