Rumah  >  Artikel  >  pembangunan bahagian belakang  >  Memperkukuh langkah keselamatan untuk permulaan: Panduan

Memperkukuh langkah keselamatan untuk permulaan: Panduan

WBOY
WBOYasal
2023-09-03 10:45:021354semak imbas

Memperkukuh langkah keselamatan untuk permulaan: Panduan

Tutorial ini adalah sebahagian daripada siri "Bina Permulaan Anda dengan PHP" di Envato Tuts+. Dalam siri ini, saya akan membimbing anda melalui pelancaran permulaan daripada konsep kepada realiti, menggunakan apl perancang mesyuarat saya sebagai contoh kehidupan sebenar. Setiap langkah, saya akan mengeluarkan kod Perancang Mesyuarat sebagai contoh sumber terbuka yang boleh anda pelajari. Saya juga akan menangani isu perniagaan berkaitan permulaan yang timbul.

Dalam episod terakhir, saya terutamanya memperkenalkan keselamatan pelayan web dan kawalan akses. Dalam rancangan hari ini, saya akan membincangkan perlindungan tambahan yang telah saya tambahkan pada Perancang Mesyuarat. Memandangkan semua kod telah ditulis dalam rangka kerja Yii2 PHP, saya dapat memanfaatkan rangka kerja untuk banyak kubu. Jika anda ingin mengetahui lebih lanjut tentang Yii2, lihat siri selari kami "Pengaturcaraan dengan Yii2."

Anda boleh mencuba perancang mesyuarat sekarang dengan menjadualkan mesyuarat pertama anda. Sila berasa bebas untuk menyiarkan maklum balas tentang pengalaman anda dalam ulasan di bawah. Saya juga terbuka kepada idea untuk ciri baharu dan cadangan topik untuk tutorial masa hadapan.

Keselamatan yang dipertingkatkan

Melaksanakan tahap keselamatan yang berbeza untuk Perancang Mesyuarat mengambil masa beberapa jam. Memandangkan pelayan dikonfigurasikan dengan lebih mantap, saya ingin membimbing anda melalui kawasan keselamatan lain bagi kod aplikasi anda.

Lindungi kunci dan kod

Jelas sekali, penting untuk menjauhkan kunci pengesahan anda daripada penggodam, tetapi juga mudah untuk menerbitkannya ke GitHub. Terdapat laporan mengenai fail disemak masuk secara tidak sengaja menggunakan kata laluan perkhidmatan atau kunci API.

Untuk mengelakkan perkara ini berlaku dalam Yii, saya menyimpan fail .ini luaran di luar pepohon kod. Ini akan dimuatkan di bahagian atas /frontend/config/main.php dan digunakan untuk sebarang konfigurasi komponen yang diperlukan:

<?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'],
                  ],

Dalam contoh di atas, anda boleh melihat rahsia API Facebook dimuatkan daripada fail permulaan.

Format fail permulaan agak mudah:

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 menggalakkan anda meletakkan beberapa tetapan ini dalam direktori /environments, terutamanya jika tetapan berbeza antara pembangunan dan pengeluaran.

Oleh itu, adalah penting bahawa fail .gitignore anda mengecualikan versi tempatan fail ini:

#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

Berikut ialah contoh salah satu fail parameter tempatan saya, /frontend/config/params-local.php:

<?php
return [
  'ga' => 'UA-xxxxxxxxxx-12',
  'urlPrefix' => '',
  'google_maps_key' => 'AIzzzzzz1111222222xxxxxxQ',
];

Saya mungkin boleh meluangkan lebih banyak masa untuk mengatur perkara ini dengan lebih baik.

Sekat pendaftaran yang tidak baik

Memperkukuh langkah keselamatan untuk permulaan: Panduan

Untuk versi Alpha, saya menghantar kemas kini secara berkelompok. Selain itu, pada hari-hari awal Meeting Planner, bilangan e-mel buruk adalah lebih tinggi daripada yang saya jangkakan. Mailgun memudahkan untuk mengenal pasti lantunan dan kegagalan:

$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', ];

Kebanyakan perkara ini mungkin berlaku apabila perancang mesyuarat melahu apabila ia mula-mula keluar - semasa rawatan dan pembedahan tumor otak saya.

Baru-baru ini, saya memudahkan untuk mendaftar untuk Meeting Planner dengan menambahkan log masuk sosial, tetapi pendaftaran spam masih boleh dilakukan. Saya mahu menyukarkan orang ramai untuk mendaftar dengan e-mel yang buruk.

Nasib baik, Yii menyediakan beberapa ciri untuk menyokong fungsi ini.

Kod pengesahan

Yii2 kini menyediakan kod pengesahan terbina dalam. Oleh itu, sesiapa yang mendaftar menggunakan kaedah e-mel dan kata laluan lama perlu memasukkan kod pengesahan. Anda boleh melihat medan captcha di bawah: captcha 字段:

<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>

然后,将验证码合规性添加为 SignupForm 模型的规则:

<?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'],
        ];
    }

如果人们没有输入正确的验证码响应,他们就无法注册。这使得垃圾邮件发送者很难进行自动注册。

检查DNS

我还想尽量减少使用虚假电子邮件地址进行注册的情况。 Yii 的 checkDNS 验证实际上会根据电子邮件地址的域查找有效的 MX 记录:

['email', 'email', 'checkDNS'=>true, 'enableIDN'=>true],

例如,如果我将 gmail.com 误输入为 gmal.com,则 checkDNS 将返回 false。 gmal.com 没有注册 MX 记录。同样,spambotolympics9922.com 也没有。

最终,安全性是一个迭代过程。总是有更多事情要做。

限制滥用行为

接下来,我想为人们可以执行的操作数量添加常见限制,以限制滥用并防止应用程序变得笨拙。

会议创建

为了防止人们创建大量空会议,我创建了一个 findEmptyMeeting ,它会查找空会议并在有人尝试创建新会议时重用它:

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]);
    }

换句话说,如果用户创建新会议 1,700 次,他们将始终看到他们创建的第一个空会议。

限制操作频率

我还创建了一个通用结构的 withinLimit

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;        
    }

Kemudian, tambahkan pematuhan captcha sebagai peraturan untuk model SignupForm: 🎜
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']);
        }
    
🎜Jika orang tidak memasukkan respons captcha yang betul, mereka tidak boleh mendaftar. Ini menyukarkan pengirim spam untuk mengautomasikan pendaftaran. 🎜 🎜Semak DNS🎜 🎜Saya juga ingin meminimumkan penggunaan alamat e-mel palsu untuk mendaftar. Pengesahan checkDNS Yii sebenarnya mencari rekod MX yang sah berdasarkan domain alamat e-mel: 🎜
  const MEETING_LIMIT = 7;
🎜Sebagai contoh, jika saya tersilap memasukkan gmail.com sebagai gmal.com, checkDNS akan mengembalikan false. gmal.com tidak mempunyai rekod MX berdaftar. Begitu juga, spambotolympics9922.com tidak. 🎜 🎜Akhirnya, keselamatan adalah proses berulang. Selalu ada lagi yang perlu dilakukan. 🎜 🎜Hadkan penyalahgunaan🎜 🎜Seterusnya, saya ingin menambah had biasa pada bilangan tindakan yang boleh dilakukan oleh orang ramai untuk mengehadkan penyalahgunaan dan menghalang apl daripada menjadi sukar digunakan. 🎜 🎜Penciptaan Pertemuan🎜 🎜Untuk menghalang orang ramai daripada membuat banyak mesyuarat kosong, saya telah mencipta findEmptyMeeting yang akan mencari mesyuarat kosong dan menggunakannya semula apabila seseorang cuba mencipta mesyuarat baharu mesyuarat:
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;
    }
🎜Dalam erti kata lain, jika pengguna mencipta mesyuarat baharu sebanyak 1,700 kali, mereka akan sentiasa melihat mesyuarat kosong pertama yang mereka buat. 🎜 🎜Hadkan kekerapan operasi🎜 🎜Saya juga mencipta kaedah withinLimit bagi struktur generik untuk digunakan semula di sekeliling aplikasi, ini menghalang terlalu banyak operasi daripada dilakukan dalam tempoh yang singkat. Contoh berikut menyemak sama ada bilangan mesyuarat yang dibuat dalam jam lalu dan hari terakhir tidak melebihi n: 🎜
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 作业

今天最后,我想确保对远程 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。还有更多重要功能即将推出。

相关链接

  • 会议策划
  • 关注会议策划者的资金概况
  • 建立您的初创公司:基本安全性 (Envato Tuts+)
  • 使用 Yii2 编程:安全性 (Envato Tuts+)
  • Yii2 开发者交流会

Atas ialah kandungan terperinci Memperkukuh langkah keselamatan untuk permulaan: Panduan. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn