Deze zelfstudie maakt deel uit van de Bouw je Startup met PHP-serie op Envato Tuts +. In deze serie begeleid ik je door het opstarten van een startup van concept naar realiteit met behulp van mijn Meeting Planner app als een realistisch voorbeeld. Elke stap die ik doe, zal ik de Meeting Planner-code vrijgeven als open-source voorbeelden waar je van kunt leren. Ik zal ook opstartgerelateerde zakelijke problemen aanpakken zodra deze zich voordoen.
In de vorige aflevering behandelde ik voornamelijk webserverbeveiliging en toegangscontrole. In de aflevering van vandaag zal ik bespreken aanvullende veiligheidsmaatregelen die ik heb toegevoegd aan Meeting Planner. Omdat alle code is geschreven in het Yii2 Framework voor PHP, kon ik het framework gebruiken voor een aantal van deze vestingwerken. Als je meer wilt weten over Yii2, bekijk dan onze parallelle serie Programming With Yii2.
U kunt Meeting Planner nu uitproberen door uw eerste vergadering te plannen. Voel je vrij om feedback te geven over je ervaringen in de reacties hieronder. Ik sta ook open voor nieuwe functie-ideeën en suggesties voor onderwerpen voor toekomstige zelfstudies.
Het implementeren van de verschillende beveiligingsniveaus voor Meeting Planner zal verschillende afleveringen duren. Nu de server robuuster is geconfigureerd, wil ik u door andere beveiligingsgebieden voor de toepassingscode leiden.
Het is duidelijk dat het belangrijk is om sleutels van hackers te blijven authenticeren, maar het is ook vrij eenvoudig om ze naar GitHub te publiceren. Verhalen worden verteld over het per ongeluk inchecken van bestanden met een servicewachtwoord of API-sleutel.
Om dit in Yii te voorkomen, bewaar ik een extern INI-bestand buiten de codestructuur. Deze wordt geladen aan de bovenkant van /frontend/config/main.php en wordt gebruikt voor elke gewenste componentconfiguratie:
'mp-frontend', 'naam' => 'Meeting Planner', 'basePath' => dirname (__ DIR__), 'bootstrap' => ['log'], 'controllerNamespace' => 'frontend \ controllers', 'componenten '=> [' authClientCollection '=> [' class '=>' yii \ authclient \ Collection ',' clients '=> [' facebook '=> [' class '=>' yii \ authclient \ clients \ Facebook ', 'clientId' => $ config ['oauth_fb_id'], 'clientSecret' => $ config ['oauth_fb_secret'],],
In het bovenstaande voorbeeld kunt u de geheimen van de Facebook-API uit het initialisatiebestand laden.
Het formaat van het initialisatiebestand is redelijk eenvoudig:
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: // api.mailgun.net/v2" mailgun_public_key = "pubkey-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" oauth_fb_id = "1xxxxxxxxxxxxxxxxxxx3" oauth_fb_secret = "bcxxxxxxxxxxxxxxxxxxxda"
Yii2 raadt u aan om sommige van deze instellingen in de directory / environments te plaatsen, vooral als de instellingen verschillen tussen ontwikkeling en productie.
Het is dus belangrijk dat uw .gitignore-bestand de lokale versies van deze bestanden uitsluit:
#local milieu bestanden /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 is een voorbeeld van een van mijn lokale parameterbestanden, /frontend/config/params-local.php:
'UA-xxxxxxxxxx-12', 'urlPrefix' => ", 'google_maps_key' => 'AIzzzzzz1111222222xxxxxx',];
Ik zou waarschijnlijk nog meer tijd kunnen besteden aan het beter organiseren van deze.
Voor de alpha-release heb ik updates in waves verzonden. En in de vroege stadia van Meeting Planner waren er meer e-mails dan ik had verwacht. Mailgun maakte het gemakkelijk om de bounces en storingen te identificeren:
$ 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] ',' be @ 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 ',' [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. test. [email protected] ',' j @ c. com ',' Agung. [email protected] ',' [email protected] ',' [email protected] ',' ed @ ed. fl ',' [email protected] ',];
De meeste van deze zijn waarschijnlijk het gevolg van de tijdspanne waarin Meeting Planner nieuw was en stilzat, tijdens mijn hersentumorbehandeling en -chirurgie.
Meer recent, door het toevoegen van sociale aanmeldingen, heb ik me gemakkelijk aangemeld bij Meeting Planner, maar spamregistraties zijn nog steeds mogelijk. Ik wilde het moeilijker maken voor mensen om zich te registreren met slechte e-mails.
Gelukkig biedt Yii een aantal functies die dit ondersteunen.
Yii2 biedt nu een ingebouwde captcha. Iedereen die zich aanmeldt met de oude e-mail- en wachtwoordmethode, moet dus een captcha invoeren. Je kan de ... zien captcha
onderstaande veld:
Of vul de volgende velden in om handmatig te registreren:
'Form-registratie']); ?> = $form->veld ($ model, 'gebruikersnaam')?> = $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 (), [// configureer hier extra widget eigenschappen])?>= Html::submitButton('Signup', ['class' => 'btn btn-primary', 'name' => 'signup-button'])?>
Vervolgens wordt de naleving van de captcha als regel toegevoegd voor de SignupForm
model:
'trim'], ['gebruikersnaam', 'verplicht'], ['gebruikersnaam', 'uniek', 'targetClass' => '\ common \ models \ User', 'message' => 'Deze gebruikersnaam is al in gebruik . '], [' gebruikersnaam ',' string ',' min '=> 2,' max '=> 255], [' email ',' filter ',' filter '=>' trim '], [' email ',' vereist '], [' email ',' email ',' checkDNS '=> true,' enableIDN '=> true], [' email ',' unique ',' targetClass '=>' \ common \ modellen \ Gebruiker ',' bericht '=>' Dit e-mailadres is al in gebruik. '.Html :: a (' Op zoek naar je wachtwoord? ', [' Site / verzoek-wachtwoord-reset '])], [' wachtwoord ',' verplicht '], [' wachtwoord ',' string ',' min '=> 6], [' captcha ',' vereist '], [' captcha ',' captcha '],];
Als mensen niet de juiste captcha-reactie invoeren, kunnen ze zich niet aanmelden. Dit maakt automatische registratie moeilijk voor spammers.
Ik wilde ook de registratie minimaliseren met een nep-e-mailadres. Yii's checkDNS
validatie zoekt eigenlijk naar een geldig MX-record op basis van het domein van het e-mailadres:
['email', 'email', 'checkDNS' => true, 'enableIDN' => true],
Dus, bijvoorbeeld, als ik gmail.com verkeerd typeerde als gmal.com, checkDNS
komt terug vals
. Er is geen geregistreerd MX-record voor gmal.com. Evenzo is er niets voor spambotolympics9922.com.
Uiteindelijk is beveiliging een iteratief proces. Er is altijd meer te doen.
Vervolgens wilde ik gemeenschappelijke limieten toevoegen aan het aantal acties dat mensen konden uitvoeren, om misbruik te beperken en om de applicatie niet log te houden..
Om te voorkomen dat mensen veel lege vergaderingen maken, heb ik een gemaakt findEmptyMeeting
die op zoek is naar een lege vergadering en deze opnieuw gebruikt wanneer iemand een nieuwe probeert te maken:
public function actionCreate () // voorkom het aanmaken van talloze lege meetings $ meeting_id = Meeting :: findEmptyMeeting (Yii :: $ app-> user-> getId ()); // echo $ meeting_id; exit; if ($ meeting_id === false) // anders een nieuwe vergadering maken $ model = new Meeting (); $ model-> owner_id = Yii :: $ app-> gebruiker-> 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]);
Met andere woorden, als een gebruiker 1.700 keer een nieuwe vergadering gaat maken, krijgt deze altijd de eerste lege vergadering die ze hebben gemaakt.
Ik heb ook een algemeen gestructureerde gemaakt withinLimit
methode voor hergebruik rond de applicatie die te veel acties in een te korte tijd zou kunnen voorkomen. Het onderstaande voorbeeld controleert of er niet meer dan n aantal vergaderingen zijn gemaakt in het laatste uur en de laatste dag:
public static function withinLimit ($ user_id, $ minutes_ago = 180) // hoeveel vergaderingen door deze gebruiker in de afgelopen $ minutes_ago $ cnt = Meeting :: find () -> where (['owner_id' => $ user_id]) -> enWhere ('created_at>'. (time () - ($ minutes_ago * 60))) -> count (); if ($ cnt> = Meeting :: NEAR_LIMIT) return false; // laatste check-in 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;
Telkens wanneer iemand probeert een vergadering te maken, controleren we dit withinLimit
om te zien of ze kunnen. Zo niet, dan laten we het zien flash
foutmelding:
public function actionCreate () if (! Meeting :: withinLimit (Yii :: $ app-> user-> getId ())) Yii :: $ app-> getSession () -> setFlash ('error', Yii: : t ('frontend', 'Sorry, er zijn grenzen aan hoe snel je vergaderingen kunt maken.Ga naar support als je hulp nodig hebt.')); return $ this-> redirect (['index']);
Ik wilde ook het totale aantal acties beperken. Elke deelnemer aan een vergadering kan bijvoorbeeld slechts zeven vergaderingsdatums per vergadering toevoegen. Binnen MeetingTime.php stel ik in MEETING_LIMIT
, dus het kan later worden gewijzigd:
const MEETING_LIMIT = 7;
Dan, MeetingTime :: withinLimit ()
controleert of er door elke gebruiker niet meer dan zeven keer is gesuggereerd:
public static function withinLimit ($ meeting_id) // hoeveel vergadertijden toegevoegd aan deze vergadering $ cnt = MeetingTime :: find () -> where (['meeting_id' => $ meeting_id]) -> count (); // per gebruiker limietoptie: -> where (['suggestions_by' => $ user_id]) if ($ cnt> = MeetingTime :: MEETING_LIMIT) return false; return true;
Wanneer ze een maken Ontmoetingstijd
, de controller-creëringsmethode controleert de limieten:
public function actionCreate ($ meeting_id) if (! MeetingTime :: withinLimit ($ meeting_id)) Yii :: $ app-> getSession () -> setFlash ('error', Yii :: t ('frontend', 'Sorry , u heeft het maximale aantal datumtijden per vergadering bereikt Neem contact op met ondersteuning als u extra hulp nodig heeft of feedback wilt geven. ')); return $ this-> redirect (['/ meeting / view', 'id' => $ meeting_id]);
Tot slot wilde ik vandaag de toegang tot externe cron-taken beveiligen. Er zijn enkele interessante benaderingen beschreven op de interwebs. Voor nu, controleer ik dat het $ _SERVER [ 'REMOTE_ADDR']
(het verzoekende IP-adres) is dezelfde server als de hosting $ _SERVER [ 'SERVER_ADDR']
, het lokale IP-adres. $ _SERVER [ 'REMOTE_ADDR']
is veilig om te gebruiken voor de veiligheid - met andere woorden, ik heb gelezen dat het niet kan worden vervalst.
// alleen cron-taken en -beheerders kunnen de acties van deze controller uitvoeren in public-functie vóór Action (actie $) // uw aangepaste code hier, als u wilt dat de code wordt uitgevoerd vóór actiefilters // die worden geactiveerd op [[EVENT_BEFORE_ACTION]] evenement, bijv PageCache of AccessControl if (! Parent :: beforeAction ($ action)) return false; // andere aangepaste code hier als (($ _SERVER ['REMOTE_ADDR'] == $ _SERVER ['SERVER_ADDR']) || (! \ Yii :: $ app-> user-> isGuest && \ common \ models \ User :: findOne (Yii :: $ app-> user-> getId ()) -> isAdmin ())) return true; return false; // of false om de actie niet uit te voeren
Voor mijn eigen testen, staat ik ook een ingelogde beheerder toe om cron-taken uit te voeren.
Uiteindelijk kan ik ook een wachtwoord toevoegen aan mijn cron-taken en deze verplaatsen naar opdrachtregelbewerkingen.
Ik heb in de afgelopen twee afleveringen veel beveiligingsverbeteringen doorgevoerd, maar er is nog meer te doen. Op mijn shortlist staat een diepere beoordeling van de toegangsbeveiliging, met name via AJAX, het volgen en blokkeren van IP-adressen en het zorgvuldig filteren van alle gebruikersinvoer.
Nogmaals, waar wacht je nog op? Plan uw eerste vergadering en deel uw feedback in de opmerkingen. Ik zou ook uw opmerkingen over beveiligingsproblemen op prijs stellen.
Zoals altijd kun je kijken naar komende tutorials in de Building Your Startup With PHP-serie of volg me @reifman. Er komen nog een paar grote functies aan.