協會要舉辦信息安全大賽了,初賽的web+crypto+misc主要由我來出題,註冊、比賽的平臺也都要由我來寫php
上週日完成了註冊頁面的後端(前端由另外一個女生寫的),前天下午大概完成了比賽平臺的全部基本功能(前端也是由我寫的...)前端
獨立寫完比賽平臺,有些收穫打算寫在這裏,先留個坑,等比賽完了再填坑mysql
後端:PHPweb
數據庫:MySQLsql
登陸界面的前端是直接找的一個比較簡樸的框架。數據庫
後端檢驗用戶的輸入,隊伍名是隻容許出現中英文、數字及下劃線的,我用的preg_match()進行正則匹配後端
if(!preg_match('/^(?!_)[A-Za-z0-9_\x{4e00}-\x{9fa5}]+$/u',$_POST['team'])) { echo "<h2 align='center'><font color='#FF00000'>隊名只能包含中英文、數字及下劃線!</h2>"; }
驗證合法後,鏈接MySQL,採用php裏mysqli擴展的預編譯執行SQL語句(防注入),查詢隊伍是否存在安全
1 //數據庫鏈接 2 $con = new mysqli('localhost',username,password,database); 3 if ($con->connect_error) { 4 die("鏈接失敗: " . $con->connect_error); 5 } 6 // 預處理及綁定 7 $stmt = $con->prepare("SELECT team,pwd FROM teams WHERE team=? AND pwd=?"); 8 $stmt->bind_param("ss", $team,$pwd); 9 // 執行成功 10 if($stmt->execute()){ 11 $stmt->store_result(); //取回結果 12 if(($stmt->num_rows())==1){ 13 $_SESSION['team'] = $team; //記錄一個Session 14 header("Refresh:0;url=index.php"); //登錄成功跳轉至主頁 15 }else{ 16 echo "<h2 align='center'><font color='#FF00000'>隊名或密碼錯誤!</h1>"; 17 } 18 }
思考:一個CTF平臺應該具有些什麼基礎的功能?session
1.發公告的首頁框架
2.隊伍得分的排行榜
3.比賽作題的界面(重點)
4.註銷
以上四點是我以爲一個CTF平臺應具有的最基礎的功能
另外可擴展的功能有好比:*查看隊伍信息(包括成員、作題狀況等),*後臺管理頁面等
因爲時間較緊迫,初賽比較小型,因此就沒寫那麼多,之後有時間再多擴展些功能
平臺的前端也是找的一個比較清新的導航界面框架
上面的導航欄能夠隨鼠標向下滑動而上移
數據庫存了隊伍的隊名、密碼、隊長+成員、得分、各個題是否已作的信息。因爲怕本身寫的平臺有漏洞,就沒有把flag放在數據庫中。
值得注意的是,得分的那一個字段須要定義爲int類型,不能定義爲varchar類型,不然後面按得分排名時會出錯
對隊伍的身份認證採用Session會話管理,用session記錄隊名,而且在作題頁面中,會先查詢隊伍作題狀況並記入session中。已作的題就會在題旁邊顯示已作,而且不容許再重複提交flag
平臺上的每一個界面一開始都要檢查用戶是否已登陸
session_start(); if(!isset($_SESSION['team'])){ $login = false; }else{ $login = true; }
在每一個功能頁面都包含這段代碼,檢查$login的值就行
若已登陸,導航欄是這樣的
未登陸是這樣的
排行榜比較簡單,查詢數據庫按分數排名,循環打印出來
$sql = "SELECT team,leader,member1,member2,score FROM teams ORDER BY score DESC"; if($res = mysqli_query($con,$sql)){ $num = 1; while($row = mysqli_fetch_assoc($res)){ echo " <tr> <td class='a'>".$num."</td> <td class='b'>".$row['team']."</td> <td class='c'>".$row['leader']." ".$row['member1']." ".$row['member2']."</td> <td class='d'>".$row['score']."</td> </tr>"; $num++; } }
因爲前端不太會..js也不太會,不知道怎麼寫出ctfd那樣的效果,只好用table來裝各個題了...
效果是這樣的
由於沒寫後臺,因此這些題都是直接在源代碼裏添加修改
在題目旁邊會檢查隊伍是否已作出該題
if(@$_SESSION['web1']=='1'){ echo ' <font color="#32CD32">已解決√'; }
驗證flag時,我是將flag以及題目的分值放在一個配置文件裏,提交flag時將其包含
檢驗flag代碼以下
if(isset($_POST['web1submit'])){ if(!empty($_POST['web1flag'])){ if($_SESSION['web1']==0){ if(@$_POST['web1flag']===$web1flag){ require("mysqlcon.php"); // 查詢隊伍當前分數 $sql = "SELECT score FROM teams WHERE team='".$_SESSION["team"]."'"; if($res = mysqli_query($con,$sql)){ while($row = mysqli_fetch_assoc($res)){ $score = $row['score']; } } // 加分 $score += $web1score; // 更新分數 $sql = "UPDATE teams SET score='".$score."' WHERE team='".$_SESSION["team"]."'"; if(mysqli_query($con,$sql)){ // 更改web1列記錄已作 $sql = "UPDATE teams SET web1=1 WHERE team='".$_SESSION["team"]."'"; if(mysqli_query($con,$sql)){ echo '<br><font color="#32CD32">正確√'; } } mysqli_close($con); }else{ echo '<br><font color="#FF00000">錯誤×'; } }else{ echo '<br><font color="#FF00000">請勿重複答題!'; } } }
1.【單雙引號】
經過此次寫這個平臺,才瞭解到php中單雙引號的使用仍是有很大區別的,主要區別在於單引號會把【引號內徹底當字符解析】,而雙引號會【解析引號內的簡單變量】,更厲害的是花括號{}——能夠解析更復雜的變量
缺陷就有不少了,好比,
代碼冗長,無後臺管理界面,對隊伍相關信息的操做修改也不方便,出新題也不方便等等,這些也就只有慢慢優化改善這個平臺了