Avatar billede nicholas- Nybegynder
20. september 2007 - 12:59 Der er 22 kommentarer

SIkkerhed omkring PHP og webshop

Hej,

Jeg har lige bygget en webshop op helt fra bunden. Det jeg gerne vil vide lidt om, og have folk til at tjekke er sikkerhed omkring den.

Det er f.eks. lige lykkedes mig meget let, at gennemføre en ordre på en unangivet rimelig stor webshop uden at betale, fordi de ikke validerer deres input ordentligt. Har sendt dem en mail og forklaret dem at de har et problem.

Men har folk herinde ikke lyst til at give lidt feedback til hvad man skal være opmærksom på? Tror mange herinde er nysgerrige omkring det.

Hvis i har lyst til at tjekke min shop i gennem for sikkerhed, må i meget gerne sige til, så poster jeg lige linket.
Avatar billede rax Praktikant
20. september 2007 - 13:28 #1
Hej,

Jeg vil da meget gerne se din shop igennem ved lejlighed :)

Der er en række forbehold du skal tage, når du implementerer en webshop, hvad angår sikkerhed. Heriblandt er det især vigtigt, at

- Validerer samtlige brugerinput, som du selv nævner. Ikke mindst for at undgå hackerangreb, såsom cross-side scripting og SQL-injections. Det er altid bedre at lave en liste over input man accepterer, og så rejecte alt andet, end at lave en liste over ting man ikke accepterer, og tillade alt andet. Det giver langt bedre føling over, hvad der kommer ind i dit system.

- Kontroller for hvért step i din shop, at brugeren er logget korrekt ind (hvis det er nødvendigt), og har de korrekte rettigheder.

- En nyoprettet bruger bør enten følge et aktiveringslink, eller logge sig ind via et auto-genereret password, før sitet kan anvendes. Det sikre, at der ikke er en eller anden spider, som crawler over dit site og lægger ordrer ind.

- Undlad at have href="mailto:xx@xxx.xx" links på dit site, da disse nemt bliver crawlet, og anvendt til spam.

- Andvend hashing af kodeord. Det giver en rigtig god beskyttelse mod, at nogle udefrakommende skulle tilsnige sig adgang til dine brugeres informationer, og handle i deres navn.

- Nu ved jeg ikke om du har valgt selv at implementere en betalingsgateway, eller om du gør brug af 3. parts, men under alle omstændigheder bør denne køre over en 128-bit krypteret SSL linie (går jeg ikke ud fra er nødvendigt at nævne, men er taget med alligevel)

Det var lige et par stykker fra hoften.. vigtige er de allesammen, men vigtigst er nok nummer 1. Praktisér "defensive programming", og valider samtlige input grundigt, så er du i de fleste tilfælde rigtig godt stillet.
Avatar billede nicholas- Nybegynder
20. september 2007 - 16:52 #2
Hey
Tak for feedback.

Helt sikkert vigtige punkter. Nu bruger jeg ikke login selv, da jeg har indtrykket af at folk synes det er meningsløst, og diverse blog indlæg rundt omkring på nettet bekræfter også dette. Men for folk der gør er det godt at vide.

For at forhindre SQL-injections, har jeg udover validation htmlentities(addslashes(værdi)) rundt om alt der ryger ind i en mysql_query. Er det en god måde at sikre sig på? HVad med cross-side scripting, hvad er det hel præcit at der kan ske der?

Jeg bruger betalingsgateway fra 3. part (Epay).


Min webshop er indtil videre på www.nicker.dk. Den er ikke helt færdig, men der mangler ikke meget.
Avatar billede rax Praktikant
21. september 2007 - 08:55 #3
htmlentities(addslashes(value)) er et rigtig godt udgangspunkt, og sikre dig imod en lang række utilsigtede handlinger. Jeg vil dog anbefale dig også at validere dine input op imod regulære udtryk (regular expressions), hvilket jeg selv altid gør. På den måde kan der ganske enkelt ikke komme "bad content" ind i systemet. Dog er problematikken her, at man kan ende med at lave for mange begrænsninger, så brugerne ikke har udtømmende muligheder. Det er en vurderingssag.

Anvendelse af 3. part betalingsgateway er klart at foretrække, og det regnede jeg også med at du ville gøre :)

Cross-side scripting er, når man f.eks. skriver et lille javascript ind i et inputfelt. Da PHP compiler på runtime, vil scriptet ikke blive vist, men istedet parsed og executed. En klassiker her er at redirecte folk me history objectet i javascript, til andre sider, enten med skadeligt indhold, eller måske en fishing side. Derfor skal < og > ALDRIG være tilladte, og heller ikke &lt; og &gt;, da dei nogle tilfælde kan anvendes til samme formål. Til sammenligning med virkeligheden kan det nævnes, at Microsoft Hotmail blev hacket med denne metode med 2 liniers kode for et par år siden.. så derfor, tillad ALDRIG script-tegn :)

Hvad angår login, så er det fornuftigt at lægge sig op af meningsudtalelser på nettet. I mit eget modul har jeg dog lavet det således, at det både er muligt at handle anonymt og som registreret bruger. Det vil sige, at hvis en besøgende har handlet, checkes der ved check-out, om han/hun er logget ind. Er det tilfældet, anvendes oplysningerne i databasen, og hvis ikke, vises en formular, hvor man kan indtaste sine shipping- og billinginformationer.

- rax
Avatar billede dkfire Nybegynder
21. september 2007 - 11:00 #4
Du skal lige kigge efter æ, ø og å på din side, ser ud til du har lidt problemer med at vise dem rigtig.
Avatar billede nicholas- Nybegynder
21. september 2007 - 13:44 #5
Ja har godt læst det eksempel med hotmail faktisk. Læste også at Google havde på et tidspunkt.. Det lyder rimelig farligt. Men for at undgå at < > er tilladte, skal man så lave reg. exp. på alle sine input, eller er der en anden måde at komme uden om problemet.

- F.eks. ved navn og efternavn, vil jeg gerne undgå at begrænse folk og komme til at "støde" dem hvis man nu ikke tillader deres navn, derfror tjekker den kun for om der findes input i feltet. Men bliver man stadig nødt til at lave reg. exp. for at undgå at de udfører scripts...

Ja ok det er også smart nok at have begge dele.


Ja er ved at blive gråhåret over de æ,  og å. Det er kun når man ser det AJAX overlay, at den ikke viser dem ordentligt, ikk?

Ved du hvad problemet kunne være?
Avatar billede fangel Nybegynder
21. september 2007 - 14:04 #6
En anden hyggelig one-liner (såfremt ens tekst er utf8-encodet) er denne

$val = preg_replace('!p{C}!u', '', $val);

Den fjerner lidt "underlige" tegn ("Other" klassen af utf-8 tegn..) fra ens tekststreng.. Måske burde man også fjerne Cc klassen (control-characters).. hmm.. Vil jeg lige undersøge

Og hvis man virkeligt vil, så husk at valider at ens data faktisk er utf-8 encodet (igen, såfremt at man kører med utf-8 encoding.. ) Der er en hyggelig funktion som denne:

function valid_utf8( $string ) {
    $rx  = '[\xC0-\xDF]([^\x80-\xBF]|$)';
    $rx .= '|[\xE0-\xEF].{0,1}([^\x80-\xBF]|$)';
    $rx .= '|[\xF0-\xF7].{0,2}([^\x80-\xBF]|$)';
    $rx .= '|[\xF8-\xFB].{0,3}([^\x80-\xBF]|$)';
    $rx .= '|[\xFC-\xFD].{0,4}([^\x80-\xBF]|$)';
    $rx .= '|[\xFE-\xFE].{0,5}([^\x80-\xBF]|$)';
    $rx .= '|[\x00-\x7F][\x80-\xBF]';
    $rx .= '|[\xC0-\xDF].[\x80-\xBF]';
    $rx .= '|[\xE0-\xEF]..[\x80-\xBF]';
    $rx .= '|[\xF0-\xF7]...[\x80-\xBF]';
    $rx .= '|[\xF8-\xFB]....[\x80-\xBF]';
    $rx .= '|[\xFC-\xFD].....[\x80-\xBF]';
    $rx .= '|[\xFE-\xFE]......[\x80-\xBF]';
    $rx .= '|^[\x80-\xBF]';

    return ( ! (bool) preg_match('!'.$rx.'!', $string) );
}

praktisk (returnere true/false alt efter om strengen er gyldig utf8)

Husk desuden at angiv charset til htmlentities hvis du ikke kører iso-8859-1

--

For at sikre SQL-injections findes desuden mysql_real_escape_string som sikre mod tegn der kan lave injections på MySQL..

--

Generelt kan mange problemer og huller skyldes forskellige encoding af data når de sendes ind..

--

Dit problem ang ÆØÅ er nok også utf-8/iso-8859-1 baseret. Husk, AJAX skal sendes og modtages som utf-8.. (undtagen Safari der er hr modsat og vil have iso-8859-1)

-fangel
Avatar billede fangel Nybegynder
21. september 2007 - 14:11 #7
Bah.. det skal være preg_replace('!\p{C}!u', '', $val) (back-slash før p).. (og fandt lige ud af at Cc er et subset af C.. så lærte jeg også noget idag)

-fangel
Avatar billede nicholas- Nybegynder
21. september 2007 - 14:36 #8
Altså jeg kører med:

    <meta http-equiv="Content-Language" content="da">
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">

Det er kun i AJAX - delen jeg har problemet. Er det scriptet der håndterer forespørgelsen der er kodet forkert?

Den lyder meget god den preg_replace, den vil jeg kigge mere på. Men hvilke tegn går ind under "underlige tegn"?

Det var lidt af en funktion den der valid utf8. Er det godt, eller er det overkill?
Avatar billede fangel Nybegynder
21. september 2007 - 14:43 #9
Du kan som sagt kun bruge dem hvis du kører med UTF-8 encoding (og ikke ISO-8859-1 som du pt gør. Sååh)

Og valid_utf8 ser mere skræmmende ud end den egenligt er. Den kører bare nogle checks på bytestrukturen for at se om den passer på utf-8 tegn.


"Other" består af følgende underklasser:
Cc = Control
Cf = Format
Cn = Unassigned
og sådan lignende

Dvs, det er \n, \r, \b.. Generelt alle de "lave" tegn i ASCII-tabellen...

---

Ang. AJAX, så skal data sendes som UTF-8, lige meget hvad ens meta-tags siger (dvs kør output gennem utf8_encode() før de sendes)

-fangel
Avatar billede nicholas- Nybegynder
21. september 2007 - 15:01 #10
Nå er med.. Ville du anbefale at køre UTF-8 encoding fremfor ISO-8859-1?
Avatar billede rax Praktikant
21. september 2007 - 15:02 #11
jeg ville klart anvende reg. exp. til totalt at forbyde < og >.. jeg kan umiddelbart ikke komme på nogen steder de skulle være nødvendige, ud over scripting..

og havde helt glemt mysql_real_escape_string.. den bør også klart benyttes (antaget du bruger mysql).
Avatar billede fangel Nybegynder
21. september 2007 - 15:08 #12
Med mindre man agter at være meget international er det mest et "religions"-spørgsmål.. til dansk og engelsk virker de begge lige godt...

-fangel
Avatar billede fangel Nybegynder
21. september 2007 - 15:09 #13
med det sagt - jeg synes nu jeg møder færre problemer med at jeg for blandet rundt i encodingerne efter at jeg begyndte at holde _alt_ i utf-8.. ;)

-fangel
Avatar billede olebole Juniormester
27. september 2007 - 03:02 #14
<ole>

fangel >> "Ang. AJAX, så skal data sendes som UTF-8, lige meget hvad ens meta-tags siger" ... hvorfor det? Du kan sætte en Content-Type header:

oXMLHttpRequest.open( ............ );
oXMLHttpRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=iso-8859-1");
oXMLHttpRequest.send( ............ );

- men vil man gerne kunne kommunikere med resten af verden og udveksle data (og hvad skulle meningen med WWW ellers være?), er det lettest at bruge utf-8, über alles  ;o)

/mvh
</bole>
Avatar billede olebole Juniormester
27. september 2007 - 03:09 #15
- functionen escape er således deprecated fra og med JavaScript 1.5. Den er erstattet af encodeURI og encodeURIComponent, som er utf-8 baseret
Avatar billede fangel Nybegynder
27. september 2007 - 08:01 #16
Darn - nåh, men så har jeg da også lært noget. Men faktum er stadigt at et standard AJAX går ud fra at det modtagne data er UTF-8 encodet. At man så kan ændre dette vidste jeg ikke..

-fangel
Avatar billede rax Praktikant
27. september 2007 - 14:49 #17
Lige for at dele lidt info med alle, så findes der en eBog ved navn E-Pusher, som det varmt kan anbefales at læse af alle, som overvejer at beskæftige sig med e-handel. Prisen er lidt pebret, mener det er 1.500,00 kroner for et pdf-dokument på 123 sider. Men vil man være seriøs indenfor e-handel, skulle det være pengene værd.
Avatar billede nicholas- Nybegynder
03. oktober 2007 - 01:32 #18
Fik løst mit problem med de tegn. Det var en simpel htmlentities() rundt om ouput fra database der skulle til. Så nu er der ingen problemer med det.

Men  tilbage til det med sikkerhed. Nu har jeg siddet og kæmpet med sikkerhed de sidste par dage, og validerer nu alt input til databasen. Jeg har dog opdaget et par major sikkerhedsfejl. Ved ikke om det kun gælder min eller også andre sider.

Jeg har på min side en Godkend ordre side lige før man betaler, hvor man bliver præsenteret for det samlede beløb. Fra denne side sendes så et beløb til betalingsmodulet med et hidden input. Man kan ændre i hidden input feltet, men det gør ikke så meget, da der bliver genereret en md5 streng, der bliver sammenlignet i betalingsmodulet, og hvis de ikke stemmer overens afvises betalingen. Det problem jeg har fundet, er a hvis man er på Godkend ordre siden, og åbner en side på siden i nyt vindue, så kan man tilføje en vare, uden at denne vares beløb bliver lagt til det samlede beløb. Det må anses som en sikkerhedsfejl, ikk?
Avatar billede olebole Juniormester
03. oktober 2007 - 01:43 #19
Du har ikke løst problemet. Godt nok har du trådt på termometeret, så du ikke kan se, om patienten er syg - men 'han' har stadig 41,8 i feber  ;o)

htmlentities slører kun problemet. Du kører stadig med forskelligt tegnsæt i de forskellige led af kæden og får derfor også flere problemer med tiden. Den eneste måde at løse problemet på er at bruge samme tegnsæt overalt.
Avatar billede nicholas- Nybegynder
03. oktober 2007 - 02:20 #20
Ja men hvis du bare skrev Læg i indkøbskurv eller tilføj ønskeliste på siden der blev hentet, så blev det vist uden problemer. Det var kun når indholdet blev hentet fra min database at den viste det forkert. Det var derfor jeg kom frem til løsningen med htmlentities.
Avatar billede olebole Juniormester
03. oktober 2007 - 02:32 #21
Du skal bare sørge for, din DB kører med samme tegnsæt. Hvad siger phpMyAdmin om kollationerne?
Avatar billede nicholas- Nybegynder
04. oktober 2007 - 11:54 #22
Og det var kun når indholdet fra databasen blev vist på den specifikke side der var problemer. Andre steder på sidden kører det fint. Men alle mine tabeller har kollation: latin1_swedish_ci. Det er bare ikke noget jeg har valgt selv, det må være automatisk.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester