Drupal biztonság
Ki célpont?
mi nem vagyunk célpontok Az adatok értékesek (pl. tematizált email címlista az {user} táblából) A látogatók értékesek Minden gép számít (botnetek) Vandálkodni jó :)
Ki célpont? Mindenki
Biztonságról általában Csak biztonságos és nem biztonságos oldal van, nincs félig biztonságos Egy rossz sor kód is elég ahhoz, hogy bárki bármit tehessen az oldalunkkal / szerverünkkel A webfejlesztő is programozó, ugyanúgy kell nekünk is törődnünk a biztonsággal, mint annak, aki az amerikai védelmi hivatalnak fejleszt.
Hálózati biztonság Titkosított protokollok használata (FTP és HTTP (feltöltés) kerülendő) Wi-Fi esetén WPA titkosítás Total Commander nem jelszómegőrző
Így hallgathatlak le téged
Bárki lehallgathat Nem csak a képzett crackerek sudo ifconfig wlan0 down sudo iwconfig wlan0 mode monitor sudo ifconfig wlan0 up sudo wireshark
Megoldások SSL-lel titkosított protokollok használata: FTPS SFTP HTTPS SSH VPN
Szerverbeállítások FastCGI (DDoS ellen jobb) PHP suhosin használata php.ini open_basedir disabled_functions disabled_classes safe_mode kikapcsolása (hamis biztonságérzet, gyakorlatban nem sokat véd)
Formok biztonsága a hidden (és bármilyen más) mezők tartalmai ugyanúgy módosíthatóak a felhasználók által! (meglepően sok oldal törhető így) szerencsére ezt a form api kivédi
Formok biztonsága Bizonyos érzékeny adatok (pl.: bankkártya szám) beviteli mezőjénél az autocomplete= off attribútum használata
HTTP kérések Írás soha ne legyen GET Létrehozás, szerkesztés az POST (form miatt), de a törlés is legyen az! Nem árt, ha rákérdezünk a felhasználóra törlés előtt (Drupalban: confirm_form() függvény) Ha bejut valamilyen bot, akkor a linkeken végigmegy ha ez egy admin felület, akkor törölheti az összes tartalmat
HTTP kérések Érzékeny adatot URL-ben soha http://example.com/register.php? username=foo&password=bar&mail=foobar@example.com
JavaScript A JavaScript által végzett ellenőrzés csak kényelmi szolgáltatás, minden ellenőrzést el kell végezni a szerver oldalon is!
JavaScript Valós életből vett ellenpélda: <script language="javascript"> <!--// /*This Script allows people to enter by using a form that asks for a UserID and Password*/ function pasuser(form) { if (form.id.value=="buyers") { if (form.pass.value=="gov1996") { location="http://officers.federalsuppliers.com/agents.html" } else { alert("invalid Password") } } else { alert("invalid UserID") } } //--> </script>
File inclusion File-t SOHA nem include-olunk URL alapján Triviális példa: http://example.com/index.php?p=../../../../etc/ passwd http://example.com/index.php?p=index.php
Drupal biztonság
Alapok Soha, de soha ne nyúljunk a core kódhoz!
Alapok Használjuk a Drupal függvényeit és API-jait Nálunk tapasztaltabb emberek írták Könnyű megtanulni őket Hosszú távon úgyis gyorsabban végezzük el a feladatainkat
Alapok Minimális jogosultságok mindenkinek A következő jogosultságok megadásával odaadjuk a siteunkat: Administer content types Administer users Administer permissions Administer filters Administer site configuration
Input formats Amit csak nagyon megbízható felhasználóknak engedünk: Full HTML PHP
Access control Használd: node_access user_access hook_menu
hook_menu() 'access callback' ezzel a függvénnyel ellenőrzi a Drupal, hogy az adott felhasználó jogosult-e az oldal megnézésére alapértelmezett érték: user_access 'access arguments' egy tömb, ami paraméterként adódik át user_access esetén elég egy elem, a jogosultság neve
hook_menu() Rossz példa: function hook_menu() { return array( 'foobar' => array( 'access callback' => TRUE, ), ); }
hook_menu() Még egy rossz példa function hook_menu() { } return array('foobar' => array( )); 'access callback' => user_access('some permission'),
hook_menu() Jó példa function hook_perm() { return array('do sg with my module'); } function hook_menu() { return array( 'foobar' => array( 'access arguments' => array('do sg with my module'), )); }
Valamit csinálni akarunk egy másik user nevében Rossz példa global $user; $user = user_load(1); Rossz példa global $user;... $user->uid = 1;
Valamit csinálni akarunk egy másik user nevében Jó példa global $user; drupal_save_session(false); $user = user_load(1); Ha nem muszáj a jelenlegi userre hivatkozni, akkor ne használjuk az user változót
SQL injection Nem megfelelően kezelt sztring beillesztése SQL lekérésbe Mindig kritikus hiba
SQL injection mysqli_query( SELECT * FROM node WHERE nid =. $_GET['nid']); Ez ilyesztő
SQL injection mysqli_query( SELECT * FROM node WHERE nid =. $_REQUEST['nid']); Ez még ilyesztőbb
SQL injection mysqli_query($_request['searchquery']); Ez talán a legrémesebb. Van ilyen: Google inurl:select inurl:from inurl:where
SQL injection Nem SQL injection, de sok kezdő fejlesztő beleszalad SELECT * FROM user WHERE name LIKE '% $username%'
Feltöltött fájlok Mindig ellenőrizni: méret kiterjesztés felbontás (képek esetén) file_check_location() Lehetőleg soha ne include-oljunk felhasználó által feltöltött fájlt
CSRF <img src= http://drupal.org/logout />
CSRF Cross-site request forgery
Megelőzés Ahol lehet, ott form api-t használni token használata hozzáadás: $token = drupal_get_token('foo'); l($text, some/path/$token ); ellenőrzés: function my_page_callback($args, $token) { if(!drupal_valid_token($token, 'foo')) drupal_access_denied(); else {... } }
XSS Cross site scripting
XSS példa Node címek listázása saját theme függvénnyel: $output = '<li>'. $node->title. '</li>'; return $output; Mi van, ha a node címe a következő? '<script>alert( U R H4XXD LULZ ); </script>'
XSS Nem csak vicces dialógusok feldobálásra való Bármit megtehetünk, amit az adott bejelentkezett felhasználó megtehet.
Példa $.get(drupal.settings.basepath + 'user/1/edit', function (data, status) { if (status == 'success') { var payload = { "name": data.match(/id="edit-name" size="[0-9]*" value="([a-z0-9]*)"/)[1], "mail": data.match(/id="edit-mail" size="[0-9]*" value="([a-z0-9]*@[a-z0-9]*.[a-z0-9]*)"/)[1], "form_id": 'user_profile_form', "form_token": data.match(/id="edit-user-profile-form-form-token" value="([a-z0-9]*)"/)[1], build_id: data.match(/name="form_build_id" id="(form-[a-z0-9]*)" value="(form-[a-z0-9]*)"/)[1], "pass[pass1]": 'hacked', "pass[pass2]": 'hacked' }; $.post(drupal.settings.basepath + 'user/1/edit', payload); } } );
Védekezés Csak escape-elni kell htmlspecialchars($text, ENT_QUOTES, 'UTF-8'); de nem szabad elfelejteni nem kellene többször megcsinálni abban a szövegben sem lesz markup, ahol kellene lennie
Problémák A környezet más értelmet ad a jeleknek I CAN HAZ <b>cheezburger</b> LULZ! <b> is not deprecated <span attribute= $foo >$bar</span>
Megoldások check_plain() check_markup() check_url() filter_xss() t()
check_plain() plain text környezet: <b> is not deprecated html környezet: <b> is not deprecated
check_markup() Rich text környezet [#8] foobar \n baz HTML környezet <p> <a href= http://drupal.org/node/8 > node/8 </a> foobar <br /> baz </p>
check_url() URL környezet http://asdf.com/?foo=42&bar=baz HTML környezet http://asdf.com/?foo=42&bar=baz
filter_xss() Felhasználó által adott HTML <p>foo</p><script>alert('bar');</script> Biztonságos HTML <p>foo</p>alert('bar');
filter_xss() Felhasználó által adott HTML <img src= abc.jpg onmouseover=... /> Biztonságos HTML <img src= abc.jpg />
filter_xss() Felhasználó által adott HTML <img src= javascript:dosomethingbad() /> Biztonságos HTML <img src= dosomethingbad() />
Mi mit vár HTML Sima szöveg checkboxes #options select #options radios #options l() l() drupal_set_title drupal_set_message watchdog
Mi mit vár HTML site mission slogan footer
Mi mit vár Sima szöveg termek felhasználónevek tartalomtípusok node név
Mi mit vár Rich text comment body node body
t() Plain text HTML t('@var', array('@var' => $plain_text)); @: plain text t('%var', array('%var' => $plain_text)); %: kiemelt szöveg HTML HTML t('!var', array('!var' => $html));
.htaccess Nagyon fontos fájl! Ha nincs ott, akkor könnyen okozhat sebezhetőséget pl.: directory listing + backup a settings.php-ről
Példák sebezhetőségekre Webshopnál az áru mennyisége nem 1, hanem.1 Webshop: ár eltárolása hidden mezőben, átírva 0-ra ingyen lehet rendelni
Példák sebezhetőségekre Sütiben felhasználónév vagy userid eltárolása Sok oldalnál nyitvahagyják a memcache portját (11211), így a cache-elt adatok könnyedén manipulálhatók.
További olvasnivaló http://acko.net/blog/safe-string-theory-for-the-web http://drupal.org/writing-secure-code http://drupal.org/security-team http://owasp.org http://crackingdrupal.com http://api.drupal.org
recruitment@pronovix.com Belga-magyar cég Közép-Európa egyik legjobb csapata <15 fő Utazás, csoki, sör