Construire votre démarrage renforcer la sécurité

Ce que vous allez créer

Ce tutoriel fait partie de la Construire votre démarrage avec la série PHP sur Envato Tuts +. Dans cette série, je vous guide dans le lancement d’une startup du concept à la réalité en utilisant mes Planificateur de réunion application comme exemple de la vie réelle. À chaque étape du processus, je publierai le code de Meeting Planner sous forme d’exemples open source à partir desquels vous pourrez apprendre. Je traiterai également les problèmes liés au démarrage au fur et à mesure qu'ils surviennent.

Dans l'épisode précédent, je couvrais principalement la sécurité des serveurs Web et le contrôle d'accès. Dans l'épisode d'aujourd'hui, je discuterai des garanties supplémentaires que j'ai ajoutées à Meeting Planner. Comme tout le code est écrit dans le framework Yii2 pour PHP, j'ai pu exploiter le framework pour un certain nombre de ces fortifications. Si vous souhaitez en savoir plus sur Yii2, consultez notre série parallèle Programmer avec Yii2.

Vous pouvez utiliser Meeting Planner dès maintenant en planifiant votre première réunion. N'hésitez pas à poster des commentaires sur votre expérience dans les commentaires ci-dessous. Je suis également ouvert aux nouvelles idées de fonctionnalités et suggestions de sujets pour les prochains tutoriels..

Construire une sécurité accrue

La mise en œuvre des différents niveaux de sécurité pour Meeting Planner prendra plusieurs épisodes. Maintenant que le serveur est configuré de manière plus robuste, je souhaite vous guider à travers d'autres domaines de sécurité pour le code d'application..

Protéger les clés et les codes

De toute évidence, il est important de garder les clés d'authentification éloignées des pirates informatiques, mais il est également assez facile de les publier sur GitHub. Les histoires sont racontées des enregistrements accidentels de fichiers avec un mot de passe de service ou une clé API. 

Pour éviter cela dans Yii, je conserve un fichier .ini externe en dehors de l'arborescence du code. Ceci est chargé en haut de /frontend/config/main.php et est utilisé pour toute configuration de composant nécessaire:

 'mp-frontend', 'name' => 'Meeting Planner', 'basePath' => dirname (__ DIR__), 'bootstrap' => ['log'], 'controllerNamespace' => 'frontend \ controllers', 'composants '=> [' authClientCollection '=> [' class '=>' yii \ authclient \ Collection ',' clients '=> [' facebook '=> [' class '=>' yii \ authclient \ clients \ Facebook ', 'clientId' => $ config ['oauth_fb_id'], 'clientSecret' => $ config ['oauth_fb_secret'],], 

Dans l'exemple ci-dessus, vous pouvez voir les secrets de l'API Facebook chargés à partir du fichier d'initialisation..

Le format du fichier d’initialisation est assez simple:

mysql_host = "localhost" mysql_un = "XXXXXXXXXXXXXXXXXXX" mysql_db = "XXXXXXXXXXXXXXXXXXX" MYSQL_PWD = "XXXXXXXXXXXXXXXXXXX" mailgun_user = "[email protected]" mailgun_pwd = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" mailgun_api_key = "key-9p-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" mailgun_api_url = "https: // apx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Yii2 vous encourage à placer certains de ces paramètres dans le répertoire /vironnements, en particulier lorsque les paramètres varient entre développement et production..

Il est donc important que votre fichier .gitignore exclue les versions locales de ces fichiers:

Fichiers d'environnement local /environments/prod/common/config/main-local.php /environments/prod/frontend/config/main-local.php / frontend/config/params-local.php / frontend / config / main-local .php 

Voici un exemple de l'un de mes fichiers de paramètres locaux, /frontend/config/params-local.php:

 'UA-xxxxxxxxxx-12', 'urlPrefix' => ", 'google_maps_key' => 'AIzzzzzz1111222222xxxxxxxQ',];

Je pourrais probablement passer encore plus de temps à mieux organiser ces.

Blocage des mauvaises inscriptions

Pour la version alpha, j'ai envoyé des mises à jour par vagues. Et, au début de Meeting Planner, il y avait un plus grand nombre de courriels incorrects que prévu. Mailgun facilite l'identification des rebonds et des échecs:

$ badEmails = [", '[email protected]', '[email protected]', '[email protected]', '[email protected]', '[email protected]', 'rhizalpatra @ fellow .lpkia.ac.id ',' [email protected] ',' [email protected] ',' [email protected] ',' a @ a. a ',' [email protected] ',' soyez @ yahoo.fr ',' [email protected] ',' [email protected] ',' [email protected] ',' [email protected] ',' sanjaydk @ projectdemo. biz ',' trial @ gmail .com ',' [email protected] ',' [email protected] ',' [email protected] ',' [email protected] ',' [email protected] ',' ddd @ c .hu ',' [email protected] ',' a. [email protected] ',' [email protected] ',' [email protected] ',' [email protected] ',' mike @ mike .mike ',' [email protected] ',' [email protected] ',' [email protected] ',' qweqwe @ qwe. qwe ',' [email protected] ','[email protected] ',' [email protected] ',' [email protected] ',' [email protected] ',' gnfbb @ h. vo ',' [email protected] ',' [email protected] ', 'oi. [email protected]', 'loi. [email protected]', '[email protected]', '[email protected]', '[email protected]','[email protected] ',' [email protected] ',' [email protected] ','[email protected] om ',' [email protected] ',' risitesh. [email protected] ',' [email protected] ',' [email protected] ',' [email protected] ',' [email protected] ',' [email protected] ',' noom @ gmail.com ',' [email protected] ',' [email protected] ',' [email protected] ',' [email protected] ',' [email protected] ',' asdasdr @ asd. com ',' quelque [email protected] ',' [email protected] ',' [email protected] ',' [email protected] ',' [email protected] ',' fesfe @ fseff. fes ',' [email protected] ',' [email protected] ',' [email protected] ',' [email protected] ',' [email protected] ',' [email protected] ' , '[email protected]', '[email protected]', '[email protected]', '[email protected]', '[email protected]', '[email protected]' , '[email protected]', '[email protected]', '[email protected]', 'endri. azizi. [email protected] ',' [email protected] ',' [email protected] ',' [email protected] ',' rob. tester. [email protected] ',' j @ c. com ',' Agung. [email protected] ',' [email protected] ',' [email protected] ',' ed @ ed. fl ',' [email protected] ',];

La plupart d'entre elles sont probablement dues à l'intervalle de temps entre Meeting Planner, qui était nouveau, et restait inactif pendant mon traitement et ma chirurgie pour une tumeur au cerveau. 

Plus récemment, en ajoutant les connexions sociales, j'ai simplifié l'inscription à Meeting Planner, mais l'inscription au spam est toujours possible. Je voulais rendre plus difficile l'inscription des mauvais courriels aux gens..

Heureusement, Yii offre quelques fonctionnalités qui supportent cette.

Captcha

Yii2 offre maintenant un captcha intégré. Ainsi, toute personne s’inscrivant avec la méthode de messagerie et de mot de passe de l’ancienne école doit saisir un captcha. Tu peux voir le captcha Champ ci-dessous:

Ou remplissez les champs suivants pour vous inscrire manuellement:

'inscription de formulaire']); ?> champ ($ modèle, 'nom d'utilisateur')?> field ($ model, 'email', ['errorOptions' => ['class' => 'help-block', 'encode' => false]]) -> textInput ()?> champ ($ model, 'password') -> passwordInput ()?> field ($ model, 'captcha') -> widget (\ yii \ captcha \ Captcha :: nom de classe (), [// configure les propriétés de widget supplémentaires ici])?>
'btn btn-primary', 'name' => 'bouton d'inscription'])?>

Ensuite, le respect du captcha est ajouté en règle générale pour le SignupForm modèle:

 'trim'], ['nom d'utilisateur', 'obligatoire'], ['nom d'utilisateur', 'unique', 'targetClass' => '\ common \ models \ User', 'message' => 'Ce nom d'utilisateur a déjà été utilisé . '], [' nom d'utilisateur ',' chaîne ',' min '=> 2,' max '=> 255], [' email ',' filter ',' filter '=>' trim '], [' email ',' required '], [' email ',' email ',' checkDNS '=> true,' enableIDN '=> true], [' email ',' unique ',' targetClass '=>' \ common \ models \ User ',' message '=>' Cette adresse email a déjà été prise. '.Html :: a (' Vous cherchez votre mot de passe? ', [' Site / request-password-reset '])], [' mot de passe ',' obligatoire '], [' mot de passe ',' chaîne ',' min '=> 6], [' captcha ',' requis '], [' captcha ',' captcha '],];  

Si les personnes ne saisissent pas la bonne réponse captcha, elles ne peuvent pas s'inscrire. Cela rend l'enregistrement automatisé difficile pour les spammeurs.

CheckDNS

Je voulais aussi minimiser les inscriptions avec une fausse adresse email. Yii checkDNS validation recherche en fait un enregistrement MX valide basé sur le domaine de l'adresse électronique:

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

Ainsi, par exemple, si j’ai mal typé gmail.com comme gmal.com, checkDNS résultats faux. Il n'y a pas d'enregistrement MX enregistré pour gmal.com. De même, il n'y en a pas pour spambotolympics9922.com.

En fin de compte, la sécurité est un processus itératif. Il y a toujours plus à faire.

Limiter les actions abusives

Ensuite, je voulais ajouter des limites communes au nombre d'actions que les gens pouvaient effectuer, limiter les abus et éviter que l'application ne devienne trop lourde..

Création de réunion

Pour empêcher les gens de créer beaucoup de réunions vides, j'ai créé un findEmptyMeetingqui cherche une réunion vide et la réutilise quand quelqu'un essaie d'en créer une:

fonction publique actionCreate () // empêche la création de nombreuses réunions vides $ meeting_id = Meeting :: findEmptyMeeting (Yii :: $ app-> user-> getId ()); // echo $ meeting_id; exit; if ($ meeting_id === false) // sinon, crée une nouvelle réunion $ 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]); 

En d'autres termes, si un utilisateur crée une nouvelle réunion 1 700 fois, il se verra toujours présenter la première réunion vide qu'il a créée..

Limiter la fréquence des actions

J'ai aussi créé une structure commune dans la limite méthode de réutilisation autour de l’application qui permettrait d’éviter un trop grand nombre d’actions dans un délai trop court. L'exemple ci-dessous vérifie que pas plus de n réunions ont été créées au cours de la dernière heure et du dernier jour:

Fonction statique publique insideLimit ($ user_id, $ minutes_ago = 180) // combien de réunions créées par cet utilisateur dans $ 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 () -> où (['owner_id' => $ user_id]) -> etWhere ('created_at>'. (time () - (24 * 3600)) ) -> compter (); if ($ cnt> = Meeting :: DAY_LIMIT) return false;  return true; 

Chaque fois que quelqu'un essaie de créer une réunion, nous vérifions dans la limite pour voir s'ils le peuvent. Si non, nous montrons la flash Message d'erreur:

fonction publique actionCreate () if (! Meeting :: insideLimit (Yii :: $ app-> user-> getId ())) Yii :: $ app-> getSession () -> setFlash ('error', Yii: : t ('frontend', 'Désolé, la rapidité avec laquelle vous pouvez créer des réunions est limitée. Consultez le support technique si vous avez besoin d'aide.')); retourne $ this-> redirect (['index']);  

Limiter le nombre d'actions

Je voulais aussi limiter le nombre total d'actions. Par exemple, chaque participant à la réunion ne peut ajouter que sept heures de réunion par réunion. Dans MeetingTime.php, j'ai défini MEETING_LIMIT, donc cela peut être changé plus tard:

 const MEETING_LIMIT = 7; 

ensuite, Heure de réunion :: insideLimit () vérifie que tout utilisateur n’a pas suggéré plus de sept fois:

fonction statique publique insideLimit ($ meeting_id) // combien de temps de réunion ajoutés à cette réunion $ cnt = MeetingTime :: find () -> where (['meeting_id' => $ meeting_id]) -> count (); // option de limite par utilisateur: -> where (['suggéré_by' => $ id_utilisateur]) if ($ cnt> = MeetingTime :: MEETING_LIMIT) return false;  return true; 

Quand ils vont créer un L'heure de rendez-vous, la méthode create controller vérifie les limites:

fonction publique actionCreate ($ meeting_id) if (! MeetingTime :: insideLimit ($ meeting_id)) Yii :: $ app-> getSession () -> setFlash ('erreur', Yii :: t ('frontend', 'désolé , vous avez atteint le nombre maximum de dates par réunion. Contactez le support technique si vous avez besoin d’aide supplémentaire ou si vous souhaitez faire part de vos commentaires. ')); return $ this-> redirect (['/ meeting / view', 'id' => $ meeting_id]);  

Sécurisation des emplois CRON

Enfin, aujourd’hui, je souhaitais sécuriser l’accès aux tâches cron distantes. Certaines approches intéressantes sont décrites sur les interwebs. Pour l'instant, je vérifie que le $ _SERVER ['REMOTE_ADDR'] (l'adresse IP du demandeur) est le même serveur que l'hébergement $ _SERVER ['SERVER_ADDR'], l'adresse IP locale.  $ _SERVER ['REMOTE_ADDR'] est sûr à utiliser pour la sécurité-en d'autres termes, j'ai lu qu'il ne peut pas être usurpé.

 // seuls les travaux cron et les administrateurs peuvent exécuter la fonction public des actions de ce contrôleur beforeAction ($ action) // votre code personnalisé ici, si vous voulez que le code soit exécuté avant les filtres d'action, // qui sont déclenchés sur [[EVENT_BEFORE_ACTION]] événement, par exemple PageCache ou AccessControl if (! Parent :: beforeAction ($ action)) return false;  // autre code personnalisé ici si (($ _SERVER ['REMOTE_ADDR'] == $ _SERVER ['SERVER_ADDR']) || (! \ Yii :: $ app-> user-> isGuest && \ common \ models \ User :: findOne (Yii :: $ app-> user-> getId ()) -> isAdmin ())) return true;  return false; // ou false pour ne pas exécuter l'action

Pour mes propres tests, j'autorise également un administrateur connecté à exécuter des tâches cron..

Finalement, je peux aussi ajouter un mot de passe à mes tâches cron et les déplacer vers des opérations en ligne de commande..

Regarder vers l'avant

J'ai réalisé de nombreuses améliorations en matière de sécurité au cours des deux derniers épisodes, mais il reste encore beaucoup à faire. Sur ma liste de sélection se trouve un examen approfondi de la sécurité des accès, notamment via AJAX, le suivi et le blocage des adresses IP et le filtrage minutieux de toutes les entrées utilisateur..

Encore une fois, qu'attendez-vous? Planifiez votre première réunion et partagez vos commentaires dans les commentaires. J'apprécierais également vos commentaires sur les questions de sécurité. 

Comme toujours, vous pouvez regarder les prochains tutoriels de la série Construire votre démarrage avec PHP ou suivez-moi @reifman. Il y a quelques autres fonctionnalités plus importantes à venir.

Liens connexes

  • Planificateur de réunion
  • Suivre le profil de financement de Meeting Planner
  • Construire votre démarrage: sécurité de base (Envato Tuts +)
  • Programmation avec Yii2: Sécurité (Envato Tuts +)
  • L'échange de développeurs Yii2