Dieses Tutorial ist Teil der Reihe „Build Your Startup with PHP“ auf Envato Tuts+. In dieser Serie begleite ich Sie durch die Gründung eines Startups vom Konzept bis zur Realität, wobei ich meine Meeting-Planer-App als Beispiel aus der Praxis verwende. Bei jedem Schritt werde ich den Meeting Planner-Code als Open-Source-Beispiel veröffentlichen, aus dem Sie lernen können. Ich werde auch auf auftretende Unternehmensthemen im Zusammenhang mit Startups eingehen.
In der letzten Folge habe ich hauptsächlich Webserversicherheit und Zugriffskontrolle vorgestellt. In der heutigen Show werde ich zusätzliche Schutzmaßnahmen besprechen, die ich dem Meeting Planner hinzugefügt habe. Da der gesamte Code im Yii2-Framework von PHP geschrieben wurde, konnte ich das Framework für viele Verbesserungen nutzen. Wenn Sie mehr über Yii2 erfahren möchten, schauen Sie sich unsere Parallelserie „Programmieren mit Yii2“ an.
Sie können den Meeting-Planer jetzt ausprobieren, indem Sie Ihr erstes Meeting planen. Bitte hinterlassen Sie in den Kommentaren unten Feedback zu Ihren Erfahrungen. Ich bin auch offen für Ideen für neue Funktionen und Themenvorschläge für zukünftige Tutorials.
Die Implementierung verschiedener Sicherheitsstufen für Meeting Planner dauert mehrere Stunden. Nachdem der Server nun robuster konfiguriert ist, möchte ich Sie durch andere Sicherheitsbereiche Ihres Anwendungscodes führen.
Natürlich ist es wichtig, Ihre Authentifizierungsschlüssel von Hackern fernzuhalten, aber es ist auch einfach, sie auf GitHub zu veröffentlichen. Es gab Berichte darüber, dass Dateien versehentlich mithilfe von Dienstkennwörtern oder API-Schlüsseln eingecheckt wurden.
Um dies in Yii zu verhindern, behalte ich eine externe .ini-Datei außerhalb des Codebaums. Dies wird oben in /frontend/config/main.php geladen und für alle notwendigen Komponentenkonfigurationen verwendet:
<?php $config = parse_ini_file('/var/secure/meetme.ini', true); $params = array_merge( require(__DIR__ . '/../../common/config/params.php'), require(__DIR__ . '/../../common/config/params-local.php'), require(__DIR__ . '/params.php'), require(__DIR__ . '/params-local.php') ); return [ 'id' => 'mp-frontend', 'name' => 'Meeting Planner', 'basePath' => dirname(__DIR__), 'bootstrap' => ['log'], 'controllerNamespace' => 'frontend\controllers', 'components' => [ 'authClientCollection' => [ 'class' => 'yii\authclient\Collection', 'clients' => [ 'facebook' => [ 'class' => 'yii\authclient\clients\Facebook', 'clientId' => $config['oauth_fb_id'], 'clientSecret' => $config['oauth_fb_secret'], ],
Im obigen Beispiel können Sie sehen, wie das Facebook-API-Geheimnis aus der Initialisierungsdatei geladen wird.
Das Format der Initialisierungsdatei ist ganz einfach:
mysql_host="localhost" mysql_un="xxxxxxxxxxxxxxxxxxx" mysql_db="xxxxxxxxxxxxxxxxxxx" mysql_pwd="xxxxxxxxxxxxxxxxxxx" mailgun_user = "xxxxxxxxxxxxxxxxxxx@meetingplanner.io" mailgun_pwd = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" mailgun_api_key="key-9p-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" mailgun_api_url="https://api.mailgun.net/v2" mailgun_public_key="pubkey-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" oauth_fb_id="1xxxxxxxxxxxxxxxxxxx3" oauth_fb_secret="bcxxxxxxxxxxxxxxxxxxxda"
Yii2 empfiehlt Ihnen, einige dieser Einstellungen im Verzeichnis /environments abzulegen, insbesondere wenn sich die Einstellungen zwischen Entwicklung und Produktion unterscheiden.
Es ist daher wichtig, dass Ihre .gitignore-Datei lokale Versionen dieser Dateien ausschließt:
#local environment files /environments/prod/common/config/main-local.php /environments/prod/frontend/config/main-local.php /frontend/config/params-local.php /frontend/config/main-local.php
Hier ist ein Beispiel einer meiner lokalen Parameterdateien, /frontend/config/params-local.php:
<?php return [ 'ga' => 'UA-xxxxxxxxxx-12', 'urlPrefix' => '', 'google_maps_key' => 'AIzzzzzz1111222222xxxxxxQ', ];
Ich könnte wahrscheinlich mehr Zeit damit verbringen, diese besser zu organisieren.
Für die Alpha-Version habe ich das Update stapelweise verschickt. Außerdem war in den Anfängen von Meeting Planner die Anzahl der fehlerhaften E-Mails höher als ich erwartet hatte. Mailgun erleichtert die Identifizierung von Bounces und Ausfällen:
$badEmails=[ '', 'test2@gmail.com', '1111@gmail.com', 'qwerty@gmail.com', 'amjadiqbalkhanniazi@gmail.com', 'admin@admin.com', 'rhizalpatra@fellow.lpkia.ac.id', 'tm@archi.com', 'test@test.com', 'web@yahoo.fr', 'a@a. a', 'ailaa@aa.com', 'be@yahoo.fr', 'vico@gmail.com', 'nobu@gmail.com', 'a@gmail.com', 'ct@gmail.com', 'sanjaydk@projectdemo. biz', 'trial@gmail.com', 'varlog255q@hotmail.com', 'baah@baah.com', 'minhvnn1@gmail.com', 'test@gmail.com', 'test@mediabite.co.uk', 'ddd@c. hu', 'ddd@ymail.com', 'a. chetan@saisoftex.com', 'user02@local.com', 'Imrky4@gmail.com', 'robomadybu@hotmail.com', 'mike@mike. mike', 'abcd@gmail.com', 'azazaz@azazaza.com', 'mama@mama.mn', 'qweqwe@qwe. qwe', 'testere@wp.pl', 'kaze@hotmail.com', 'test@usertest.fr', 'demodemo@demo.com', 'qqq@dd.gh', 'gnfbb@h. vo', 'admin@admin123.com', 'testsir@testsir.com', 'oi. hd@yeah1.vn', 'loi. hd@yeah1.vn', 'test@email.com', 'salom@salom.com', 'ar@yahoo.com', 'lex@gmail.com', 'Tester1234@gmail.com', 'mantaf@mail.com', 'aaa@aaa.com', 'oeui@gmail.com', 'risitesh. biswal14@yahoo.com', 'ttt@wp.pl', 'nnn@nnn.net', 'nnn2@nnn.net', 'ana@gmail.com', 'asdf@yahoo.com', 'noom@gmail.com', 'jomon@example.com', 'asdfasdf@yahoo.com', 'admin@yahoo.com', 'abinubli@mail.com', 'tes@tes.com', 'asdasdr@asd.com', 'something@some.com', 'ademin@example.com', 'd@dd.com', 'robo@gmail.com', 'toto@titi.com', 'fesfe@fseff. fes', 'master@wpthemeslist.com', 'teste@teste.com', 'barny182@hotmail.com', 'test@admin.com', 'billtian@test.com', 'Test@goggle.ca', 'jm@gmail.com', 'john-panin@qip.ru', 'loslos@loslos.com', 'ghfhf@jhgjgjk.com', 'lol@lol.com', 'tester1@gmail.com', 'g0952180828@gmail.com', 'testim@testim.com', 'mnml.name@gmail.com', 'endri. azizi. 92@gmail.com', '123123@gmail.com', 'myfriend@gmai.com', 'geraldo_1989@hotmail.com', 'rob. test. 999@gmail.com', 'j@c. com', 'Agung. andika@mhs.uinjkt.ac.id', 'W3test@ya.ru', 'user@ya.ru', 'ed@ed. fl', 'ed@ed.es', ];
Das meiste davon entstand wahrscheinlich, als der Besprechungsplaner beim ersten Erscheinen untätig war – während meiner Gehirntumorbehandlung und -operation.
Kürzlich habe ich die Anmeldung bei Meeting Planner sehr einfach gemacht, indem ich Social Login hinzugefügt habe, aber eine Spam-Registrierung ist immer noch möglich. Ich möchte es für Leute schwieriger machen, sich mit einer falschen E-Mail-Adresse anzumelden.
Glücklicherweise bietet Yii einige Funktionen zur Unterstützung dieser Funktionalität.
Yii2 bietet jetzt integrierte Bestätigungscodes. Daher muss jeder, der sich mit der alten E-Mail- und Passwortmethode registriert, einen Bestätigungscode eingeben. Sie können die captcha
Felder unten sehen:
<p>Or, fill out the following fields to register manually:</p> <div class="col-lg-5"> <?php $form = ActiveForm::begin(['id' => 'form-signup']); ?> <?= $form->field($model, 'username') ?> <?= $form->field($model, 'email', ['errorOptions' => ['class' => 'help-block' ,'encode' => false]])->textInput() ?> <?= $form->field($model, 'password')->passwordInput() ?> <?= $form->field($model, 'captcha')->widget(\yii\captcha\Captcha::classname(), [ // configure additional widget properties here ]) ?> <div class="form-group"> <?= Html::submitButton('Signup', ['class' => 'btn btn-primary', 'name' => 'signup-button']) ?> </div> <?php ActiveForm::end(); ?> </div>
Dann fügen Sie die CAPTCHA-Konformität als Regel für das SignupForm
-Modell hinzu:
<?php namespace frontend\models; use common\models\User; use yii\base\Model; use Yii; use yii\helpers\Html; use yii\validators\EmailValidator; /** * Signup form */ class SignupForm extends Model { public $username; public $email; public $password; public $captcha; /** * @inheritdoc */ public function rules() { return [ ['username', 'filter', 'filter' => 'trim'], ['username', 'required'], ['username', 'unique', 'targetClass' => '\common\models\User', 'message' => 'This username has already been taken.'], ['username', 'string', 'min' => 2, 'max' => 255], ['email', 'filter', 'filter' => 'trim'], ['email', 'required'], ['email', 'email', 'checkDNS'=>true, 'enableIDN'=>true], ['email', 'unique', 'targetClass' => '\common\models\User', 'message' => 'This email address has already been taken. '.Html::a('Looking for your password?', ['site/request-password-reset'])], ['password', 'required'], ['password', 'string', 'min' => 6], ['captcha', 'required'], ['captcha', 'captcha'], ]; }
Wenn Personen nicht die richtige Captcha-Antwort eingeben, können sie sich nicht registrieren. Dies macht es für Spammer schwierig, Registrierungen zu automatisieren.
Ich möchte auch die Verwendung gefälschter E-Mail-Adressen bei der Anmeldung minimieren. Die checkDNS
-Validierung von Yii sucht tatsächlich nach einem gültigen MX-Eintrag basierend auf der Domäne der E-Mail-Adresse:
['email', 'email', 'checkDNS'=>true, 'enableIDN'=>true],
Wenn ich beispielsweise gmail.com versehentlich als gmal.com eingebe, checkDNS
将返回 false
wird false
zurückgegeben. gmal.com hat keine registrierten MX-Einträge. Das gilt auch für spambotolympics9922.com.
Letztendlich ist Sicherheit ein iterativer Prozess. Es gibt immer mehr zu tun.
Als nächstes möchte ich allgemeine Grenzwerte für die Anzahl der Aktionen hinzufügen, die Menschen ausführen können, um Missbrauch einzuschränken und zu verhindern, dass die App unhandlich wird.
Um zu verhindern, dass Leute viele leere Meetings erstellen, habe ich ein findEmptyMeeting
erstellt, das nach leeren Meetings sucht und diese wiederverwendet, wenn jemand versucht, ein neues zu erstellen: < /p>
public function actionCreate() { // prevent creation of numerous empty meetings $meeting_id = Meeting::findEmptyMeeting(Yii::$app->user->getId()); //echo $meeting_id;exit; if ($meeting_id===false) { // otherwise, create a new meeting $model = new Meeting(); $model->owner_id= Yii::$app->user->getId(); $model->sequence_id = 0; $model->meeting_type = 0; $model->save(); $model->initializeMeetingSetting($model->id,$model->owner_id); $meeting_id = $model->id; } $this->redirect(['view', 'id' => $meeting_id]); }
Mit anderen Worten: Wenn ein Benutzer 1.700 Mal ein neues Meeting erstellt, sieht er immer das erste leere Meeting, das er erstellt.
Ich habe außerdem eine withinLimit
Methode mit einer gemeinsamen Struktur zur Wiederverwendung rund um die Anwendung erstellt. Dadurch wird verhindert, dass zu viele Vorgänge in kurzer Zeit ausgeführt werden. Das folgende Beispiel prüft, ob die Anzahl der in der letzten Stunde und am letzten Tag erstellten Besprechungen n nicht überschreitet:
public static function withinLimit($user_id,$minutes_ago = 180) { // how many meetings created by this user in past $minutes_ago $cnt = Meeting::find() ->where(['owner_id'=>$user_id]) ->andWhere('created_at>'.(time()-($minutes_ago*60))) ->count(); if ($cnt >= Meeting::NEAR_LIMIT ) { return false; } // check in last DAY_LIMIT $cnt = Meeting::find() ->where(['owner_id'=>$user_id]) ->andWhere('created_at>'.(time()-(24*3600))) ->count(); if ($cnt >= Meeting::DAY_LIMIT ) { return false; } return true; }
每当有人尝试创建会议时,我们都会检查 withinLimit
以查看他们是否可以。如果没有,我们会显示 flash
错误消息:
public function actionCreate() { if (!Meeting::withinLimit(Yii::$app->user->getId())) { Yii::$app->getSession()->setFlash('error', Yii::t('frontend','Sorry, there are limits on how quickly you can create meetings. Visit support if you need assistance.')); return $this->redirect(['index']); }
我还想限制操作的总数。例如,每个会议参与者只能为每次会议添加七个会议日期时间。在 MeetingTime.php 中,我设置了 MEETING_LIMIT
,以便稍后可以更改:
const MEETING_LIMIT = 7;
然后,MeetingTime::withinLimit()
检查以确保任何用户的建议次数不超过七次:
public static function withinLimit($meeting_id) { // how many meetingtimes added to this meeting $cnt = MeetingTime::find() ->where(['meeting_id'=>$meeting_id]) ->count(); // per user limit option: ->where(['suggested_by'=>$user_id]) if ($cnt >= MeetingTime::MEETING_LIMIT ) { return false; } return true; }
当他们去创建 MeetingTime
时,控制器创建方法会检查限制:
public function actionCreate($meeting_id) { if (!MeetingTime::withinLimit($meeting_id)) { Yii::$app->getSession()->setFlash('error', Yii::t('frontend','Sorry, you have reached the maximum number of date times per meeting. Contact support if you need additional help or want to offer feedback.')); return $this->redirect(['/meeting/view', 'id' => $meeting_id]); }
今天最后,我想确保对远程 cron 作业的访问安全。互联网上描述了一些有趣的方法。目前,我正在检查 $_SERVER['REMOTE_ADDR']
(请求 IP 地址)是否与托管 $_SERVER['SERVER_ADDR' 是同一服务器]
,本地IP地址。 $_SERVER['REMOTE_ADDR']
可以安全使用,换句话说,我已经了解到它无法被欺骗。
// only cron jobs and admins can run this controller's actions public function beforeAction($action) { // your custom code here, if you want the code to run before action filters, // which are triggered on the [[EVENT_BEFORE_ACTION]] event, e.g. PageCache or AccessControl if (!parent::beforeAction($action)) { return false; } // other custom code here if (( $_SERVER['REMOTE_ADDR'] == $_SERVER['SERVER_ADDR'] ) || (!\Yii::$app->user->isGuest && \common\models\User::findOne(Yii::$app->user->getId())->isAdmin())) { return true; } return false; // or false to not run the action }
对于我自己的测试,我还允许登录的管理员运行 cron 作业。
最终,我还可以为我的 cron 作业添加密码,并将它们移至命令行操作。
在过去的两集中,我已经完成了许多安全改进,但仍有更多工作要做。我的候选清单上包括对访问安全性的更深入审查,特别是通过 AJAX、IP 地址跟踪和阻止,以及仔细过滤所有用户输入。
再说一遍,你还在等什么?安排您的第一次会议,并在评论中分享您的反馈。我也非常感谢您对安全问题的评论。
与往常一样,您可以观看“使用 PHP 构建您的初创公司”系列中即将推出的教程,或关注我 @reifman。还有更多重要功能即将推出。
Das obige ist der detaillierte Inhalt vonStärkung der Sicherheitsmaßnahmen für Startups: Ein Leitfaden. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!