Archives pour la catégorie php

Debug PHP XDebug + VSCode

Salut à tous,

M’attaquant actuellement à de gros projets PHP avec des architectures logiciels complexe impliquant de nombreux designs patterns différents pas forcément facile à débugger (factory d’observer pour des plugins d’éditions, etc ….

Débugger à base de dump et var_dump prend du temps et n’est pas du tout performant, j’ai toujours tendance à oublié le contexte, des variables, … et je dois recommencer le debug à la main.

Continuer la lecture de Debug PHP XDebug + VSCode

Symfony, créer son propre générateur d’ID (Code jetable, …)

Salut à tous,

Dans un récent projet, j’ai dû générer des codes jetables qui n’étaient pas « devinable », j’ai découvert pour ce faire, le AbstractIdGenerator, qui permet de générer ses propres clés. (J’aurais pû le faire sur un champs à part et filtrer dessus, mais bon 🙂 … c’est d’un manque totale d’élégance intellectuelle …).

Continuer la lecture de Symfony, créer son propre générateur d’ID (Code jetable, …)

Documentation d’API automatique sur Symfony avec NelmioApiDoc

Plop à tous,

De retour en dev PHP, depuis quelques temps je me retrouve à faire des API sur Symfony (voir mon article sur FosRestBundle). Je cherchais un moyen d’automatiser la doc des API, mais aussi de pouvoir les tester côtés back sans avoir à faire de front, tout en ayant la possibilité d’utiliser des token d’authentifications, …

C’est justement ce que permet NelmioApiDoc !!

Continuer la lecture de Documentation d’API automatique sur Symfony avec NelmioApiDoc

monter un serveur PHP en une ligne de commande (ou presque)

Dans le genre « news de webg33k » en voici une …

A la base, je cherchais à utiliser/écrire un serveur http en python (pas mal de classes existent dans le domaine) pour servir une page html bidon après un man in the middle avec redirection dnspoof sur le serveur http en question, au lieu de déployer l’artillerie lourde apache ou nginx.
Continuer la lecture de monter un serveur PHP en une ligne de commande (ou presque)

Marre du spam sur wordpress ??

Plopinou …

Une rapide technique pour baisser d’un nombre assez important le spam sur un blog wordpress, en profitant de la gentillesse des spammers ^^.
En effet, la plupart du temps :

  • les ip tournent (donc impossible de bannir toutes les ip)
  • les adresses mails sont générées à la volées et comme c’est sur le domaine de gmail, bannir le domaine est impossible
  • Les commentaires changent …

Il reste donc une information qu’ils donnent, et qu’ils ne semblent pas changer … l’url de leurs sites, qui terminent toujours par « map.html » … sympa non ??

Donc pour leurs envoyer un message plein d’amour et de paix on peut gentillement modifier le fichier wp-comments-post.php : (après la ligne 38)
[sourcecode language=php]
if(preg_match("#^.*/map.html$#",$comment_author_url))
die("Go home and die!!!");
[/sourcecode]
Et voilà … 90% du spam de vos blogs devraient disparaitre. (reste plus qu’à trouver un filtre pour les casinos et on héradique toutes forme de spam sur les blogs ^^ (pas complexe je pense, mais ça fait un bail que j’en ai plus chopé donc je peux pas créer la regexp :D) ).

Petite note : J’ai testé le code ci-dessous pendant une journée et ma liste de commentaires indésirables est encore vide … ce qui est un miracle !!! Je chopais entre 25 et 50 spams par jour … (ok c’est pas beaucoup … mais c’est quand même ça de moins).

EDIT : Ne pas oublier de refaire la modification, après une mise à jour de wordpress (comme tous les fichiers sont réecrit, on perd les modifications et on remarque tout de suite le spam qui revient ;))

Administration de serveurs apache : modsecurity2

Bijour

Bé voilà vé parler du modsecurity2 … pourquoi ?? Ben on trouve pas mal de tut’s sur le net, mais c’est que pour le mod_security (sans le 2 ^^), et la syntaxe à malheureusement changée depuis.

Donc voilà …

Il faut tout d’abord rajouter un dépôt (le mien ^^) au fichier /etc/apt/sources.list :

deb http://ppa.launchpad.net/cipher.16/ppa/ubuntu intrepid main

et rajouter la clé associée au dépôt :

sudo apt-key adv --recv-keys --keyserver keyserver.ubuntu.com DA27D37831F6D1C0BC85566CDD2A2A8817FB9A87

Ensuite faire un apt-get install modsecurity2 && a2enmode mod-security2.

Pourquoi préférer cette version à celle de inittab (proposé par la doc de modsecurity) ?? … parce que c’est la dernière version stable (2.5.7, qui permet des trucs sympa … cf. la fin de l’article ;))

Par défaut, tous les fichiers de configuration liés au modsecurity2 sont bazardés dans le dossier /usr/share/apache/mod_security2_rules (je suis pas assez doué pour faire du post-install dans mes paquets …), vous pouvez soit les déplacer dans le dossier  /etc/apache2/conf.d/, mais il faudra un peu les retoucher (surtout le modsecurity_crs_10_config.conf en modifiant les fichiers de logs, sinon des erreurs apparaitront lors du démarrage du serveur).

Pour utiliser les fichiers de configuration fournit par le paquet :

cat /usr/share/apache2/mod_security2_rules/*.conf >> /etc/apache2/conf.d/security

et modifier toutes les lignes en rapport avec les logs, pour cela, remplacez :

SecAuditLog logs/modsec_audit.log par SecAuditLog /var/log/apaches2/modsec_audit.log
SecDebugLog logs/modsec_debug.log par SecDebugLog /var/log/apache2/modsec_debug.log

Ou bien, vous pouvez faire votre propre fichier de configuration, grâce à la superbe doc.

Pour cela, allez dans le dossier /etc/apache2/conf.d/ et modifiez le fichier security.conf, ou bien en créer un nommé … du nom que vous voulez.

Dans lequel il faudra mettre (au minimum, histoire de faire propre) :

<IfModule mod_security2.c>
ServerTokens Full
ServerSignature On
TraceEnable Off

SecRuleEngine On
SecRequestBodyAccess On
SecResponseBodyAccess On

SecAuditLog /var/log/apache2/mod_secure.log
## RESTE DE LA CONFIG A METTRE ICI

## NE PAS TOUCHER PLUS LOIN

Et on met quoi dans cette configuration ???

Plein de choses diverses et variées (on peut aussi rajouter quelque lignes des fichiers d’exemple dans /usr/share/apache2/mod_security2_rules, qui peuvent être très intéressante pour bloquer les injections, …).
Pour induire en erreurs/bloquer certains scanners :

Changement de la signature du serveur (un peu grossié ^^ mais ça peut induire en erreur les n00b … ça fait toujours ça de moins) :

SecServerSignature "Windows 2003 IIS/6.0"
SecRule REQUEST_HEADERS:User-Agent ".*perl.*" "t:none,msg:'Perl based user agent identified'"
SecRule REQUEST_HEADERS:User-Agent ".*nikto.*" "t:none,msg:'Nikto Scanners Identified'"
SecRule REQUEST_HEADERS:User-Agent "(?:\b(?:m(?:ozilla\/4\.0 \(compatible\)|etis)|webtrends security analyzer|pmafind)\b|n(?:-stealth|sauditor|essus|ikto)|b(?:lack ?widow|rutus|ilbo)|(?:jaascoi|paro)s|webinspect|\.nasl)" \
"phase:2,t:none,t:lowercase,deny,log,auditlog,status:404,msg:'Request Indicates a Security Scanner Scanned the Site',id:'990002',tag:'AUTOMATION/SECURITY_SCANNER',severity:'2'"
SecRule REQUEST_HEADERS_NAMES "\bacunetix-product\b" \
"phase:2,t:none,t:lowercase,deny,log,auditlog,status:404,msg:'Request Indicates a Security Scanner Scanned the Site',id:'990901',tag:'AUTOMATION/SECURITY_SCANNER',severity:'2'"
SecRule REQUEST_FILENAME "^/nessustest" \
"phase:2,t:none,t:lowercase,deny,log,auditlog,status:404,msg:'Request Indicates a Security Scanner Scanned the Site',id:'990902',tag:'AUTOMATION/SECURITY_SCANNER',severity:'2'"

Bloquer les requêtes zarb :

SecRule REQUEST_LINE "!(^((?:(?:pos|ge)t|head))|http/(0\.9|1\.0|1\.1)$)" \
"t:none,t:lowercase,msg:'Un imbécile qui connait pas le http'"

Bloquer les accès direct à l’ip du serveur : (cas courant de scan)

SecRule REQUEST_HEADERS:Host "^[\d\.]+$" \
"log,deny,status:404,t:lowercase,msg:'Connexion direct a l\'ip du serveur'"

Protection contre des fuites lors  d’erreurs mysql : (qui pourrait permettre à des petits malin de connaître les tables utilisées, …)

SecRule RESPONSE_BODY "(?:\b(?:(?:s(?:elect list because it is not contained in (?:an aggregate function and there is no|either an aggregate function or the) GROUP BY clause|upplied argument is not a valid (?:(?:M(?:S |y)|Postgre)SQL|O(?:racle|DBC)))|S(?:yntax error converting the \w+ value .*? to a column of data type|QL Server does not exist or access denied)|Either BOF or EOF is True, or the current record has been deleted(?:; the operation|\. Requested)|The column prefix .{0,50}? does not match with a table name or alias name used in the query|Could not find server '\w+' in sysservers\. execute sp_addlinkedserver)\b|Un(?:closed quotation mark before the character string\b|able to connect to PostgreSQL server:)|(?:Microsoft OLE DB Provider for .{0,30} [eE]rror |error '800a01b8)'|(?:Warning: mysql_connect\(\)|PostgreSQL query failed):|You have an error in your SQL syntax(?: near '|;)|cannot take a \w+ data type as an argument\.|incorrect syntax near (?:\'|the\b|@@error\b)|microsoft jet database engine error '8|ORA-\d{5}: )|\[Microsoft\]\[ODBC )" \
"phase:4,t:none,ctl:auditLogParts=+E,deny,log,auditlog,status:500,msg:'SQL Information Leakage',id:'970003',tag:'LEAKAGE/ERRORS',severity:'4'"

Protection contre des fuites concernant des erreurs php ou un affichage de code php (source code disclosure comme on dit :p) :

SecRule RESPONSE_BODY "<b>Warning<\/b>.{0,100}?:.{0,1000}?\bon line\b" \
"phase:4,t:none,ctl:auditLogParts=+E,deny,log,auditlog,status:500,msg:'PHP Information Leakage',id:'970009',tag:'LEAKAGE/ERRORS',severity:'4'"
SecRule RESPONSE_BODY "(?:\b(?:f(?:tp_(?:nb_)?f?(?:ge|pu)t|get(?:s?s|c)|scanf|write|open|read)|gz(?:(?:encod|writ)e|compress|open|read)|s(?:ession_start|candir)|read(?:(?:gz)?file|dir)|move_uploaded_file|(?:proc_|bz)open)|\$_(?:(?:pos|ge)t|session))\b" \
"phase:4,t:none,ctl:auditLogParts=+E,log,auditlog,msg:'PHP source code leakage',id:'970015',tag:'LEAKAGE/SOURCE_CODE',severity:'4'"
SecRule RESPONSE_BODY "<\?(?!xml)" \
"phase:4,chain,t:none,ctl:auditLogParts=+E,log,auditlog,msg:'PHP source code leakage',id:'970902',tag:'LEAKAGE/SOURCE_CODE',severity:'4'"
SecRule RESPONSE_BODY "!(?:\b(?:(?:i(?:nterplay|hdr|d3)|m(?:ovi|thd)|(?:ex|jf)if|f(?:lv|ws)|varg|cws)\b|r(?:iff\b|ar!B)|gif)|B(?:%pdf|\.ra)\b)" "t:none"

Protection contre les XSS :

SecRule REQUEST_FILENAME|ARGS|ARGS_NAMES|REQUEST_HEADERS|XML:/*|!REQUEST_HEADERS:Referer "@pm jscript onsubmit copyparentfolder javascript meta onmove onkeydown onchange onkeyup activexobject expression onmouseup ecmascript onmouseover vbscript: <![cdata[ http: settimeout onabort shell: .innerhtml onmousedown onkeypress asfunction: onclick .fromcharcode background-image: .cookie ondragdrop onblur x-javascript mocha: onfocus javascript: getparentfolder lowsrc onresize @import alert onselect script onmouseout onmousemove background application .execscript livescript: getspecialfolder vbscript iframe .addimport onunload createtextrange onload <input" \
"phase:2,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,pass,nolog,skip:1"
SecAction phase:2,pass,nolog,skipAfter:959004
SecRule REQUEST_FILENAME|ARGS|ARGS_NAMES "(?:\b(?:(?:type\b\W*?\b(?:text\b\W*?\b(?:j(?:ava)?|ecma|vb)|application\b\W*?\bx-(?:java|vb))script|c(?:opyparentfolder|reatetextrange)|get(?:special|parent)folder|iframe\b.{0,100}?\bsrc)\b|on(?:(?:mo(?:use(?:o(?:ver|ut)|down|move|up)|ve)|key(?:press|down|up)|c(?:hange|lick)|s(?:elec|ubmi)t|(?:un)?load|dragdrop|resize|focus|blur)\b\W*?=|abort\b)|(?:l(?:owsrc\b\W*?\b(?:(?:java|vb)script|shell|http)|ivescript)|(?:href|url)\b\W*?\b(?:(?:java|vb)script|shell)|background-image|mocha):|s(?:(?:tyle\b\W*=.*\bexpression\b\W*|ettimeout\b\W*?)\(|rc\b\W*?\b(?:(?:java|vb)script|shell|http):)|a(?:ctivexobject\b|lert\b\W*?\(|sfunction:))|<(?:(?:body\b.*?\b(?:backgroun|onloa)d|input\b.*?\btype\b\W*?\bimage)\b| ?(?:(?:script|meta)\b|iframe)|!\[cdata\[)|(?:\.(?:(?:execscrip|addimpor)t|(?:fromcharcod|cooki)e|innerhtml)|\@import)\b)" \
"phase:2,capture,t:none,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,log,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'950004',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2'"
SecRule REQUEST_HEADERS|XML:/*|!REQUEST_HEADERS:Referer "(?:\b(?:(?:type\b\W*?\b(?:text\b\W*?\b(?:j(?:ava)?|ecma|vb)|application\b\W*?\bx-(?:java|vb))script|c(?:opyparentfolder|reatetextrange)|get(?:special|parent)folder|iframe\b.{0,100}?\bsrc)\b|on(?:(?:mo(?:use(?:o(?:ver|ut)|down|move|up)|ve)|key(?:press|down|up)|c(?:hange|lick)|s(?:elec|ubmi)t|(?:un)?load|dragdrop|resize|focus|blur)\b\W*?=|abort\b)|(?:l(?:owsrc\b\W*?\b(?:(?:java|vb)script|shell|http)|ivescript)|(?:href|url)\b\W*?\b(?:(?:java|vb)script|shell)|background-image|mocha):|s(?:(?:tyle\b\W*=.*\bexpression\b\W*|ettimeout\b\W*?)\(|rc\b\W*?\b(?:(?:java|vb)script|shell|http):)|a(?:ctivexobject\b|lert\b\W*?\(|sfunction:))|<(?:(?:body\b.*?\b(?:backgroun|onloa)d|input\b.*?\btype\b\W*?\bimage)\b| ?(?:(?:script|meta)\b|iframe)|!\[cdata\[)|(?:\.(?:(?:execscrip|addimpor)t|(?:fromcharcod|cooki)e|innerhtml)|\@import)\b)" \
"phase:2,capture,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,log,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'959004',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2'"

Et les petits trucs que nous permettent de faire la version 2.5.7 :
(protection contre les bruteforces, il faudra bien sûr changer ARGS:login en fonction de vos champs d’authentification).

SecAction initcol:ip=%{REMOTE_ADDR},nolog
SecRule ARGS:login "!^$" \
nolog,phase:1,setvar:ip.auth_attempt=+1,deprecatevar:ip.auth_attempt=20/120
SecRule IP:AUTH_ATTEMPT "@gt 25" \
log,drop,phase:1,msg:'Possible Brute Force Attack"

Une fois que vous avez terminé votre fichier de configuration, n’oubliez pas le /etc/init.d/apache2 restart
Sinon, comme dit, ce ne sont que des exemples, … la doc est très complète : http://www.modsecurity.org/documentation/