Kebmans blogg

Hvordan kryptere passord i PostgreSQL

Posted in Data, Programmering, Teknologi by kebman on 26/08/2015

PostgreSQL kan med et enkelt håndgrep gjøre passordkryptering for deg. Alt du trenger å gjøre er å legge til en extension i psql, sånn her:

CREATE EXTENSION pgcrypto;

Så er det bare å lage en database for å teste litt:

CREATE DATABASE test;

Og en tabell for å lagre noen data med passord:

CREATE TABLE testusers (
	id SERIAL PRIMARY KEY,
	email TEXT NOT NULL,
	password TEXT NOT NULL,
);

SERIAL er her ekvivalenten til AUTO_INCREMENT i MySQL. Strengt tatt kunne vi sikkert brukt email-feltet som PRIMARY KEY, sånn som her:

CREATE TABLE testusers (
	email TEXT PRIMARY KEY,
	password TEXT NOT NULL,
);

…men jeg synes det er kjekt å kunne kalle opp en god, gammeldags ID, spesielt om det senere kan bli snakk om å utføre SQL joins. Istedenfor kan man gjøre sånn her for å sikre at email-feltet forblir unikt:

ALTER TABLE users ADD CONSTRAINT unique_email UNIQUE (email);

Men så, endelig, kan vi teste med å sette inn noe ordentlig data! For å lage skikkelig gode passord, er det ikke nok med bare en god krypteringsalgoritme. Man trenger også salt. Dette for å hindre såkalte rainbow angrep. Her er årsaken til at vi la til den extensionen i sta, for med den kan vi legge til skikkelig godt salt, sånn her:

INSERT INTO testusers(email, password) VALUES (
	'test@test.com', crypt('det_hemmelige_passordet', gen_salt('md5'))
);

Som du ser så hashes passordet med det samme det legges inn i databasen med en funksjon som heter crypt(). Denne tar to argumenter: Passordet og funksjonen gen_salt() som lager salt. For å sjekke at passordet stemmer, kan man bruke denne spørringen:

SELECT email FROM testusers WHERE id=1 AND
password=crypt('det_hemmelige_passordet', password);

Så, når dette er gjort, burde det være en smal sak å få det til å fungere med et passende serverskriptingspråk. Best av alt, skulle noen uvedkomne få tilgang til databasen, vil de uansett ikke kunne finne ut hva passordene er – ikke lett, i alle fall.

Perl-hack for å hacke terminalene i Fallout 3

Posted in Perl, Scripting, Spill by kebman on 16/07/2011

Det er ikke bare vanskelig å hacke terminalene i spillet Fallout 3 – det er også tidkrevende. Selv om du leser en kjempebra tutorial – for eksempel denne FALLOUT 3: Hacking FAQ v1.2 av Dave Bosley – så kan det ta lang tid å hacke passordet til en terminal.

Men frykt ikke. Siden det er ferie har jeg programmert to Perl-scripts som du kan bruke til å korte ned tiden det tar å hacke en terminal betraktelig.

For å bruke scriptene må du for det ha Perl installert. Har du PC må du kanskje laste det ned, mens er du så heldig å ha Mac så er det allerede forhåndsinstallert. Deretter må du kopiere koden inn i hver sin tekstfil. Kall f.eks filene for bestcandidate.pl og shortenlist.pl.

Det første skriptet brukes til å finne det beste ordet å teste først. Dette gjøres ved å finne ut hvilket ord som har mest til felles med de andre. For å bruke skriptet må du skrive ned alle ordene som kommer på terminalskjermen i spillet. Så må du kopiere dem inn på riktig plass i scriptet. Deretter må du kjøre scriptet fra kommandolinjen din, ved å skrive inn perl bestcandidate.pl.

Her er det første scriptet:

#!/usr/bin/perl
use strict;
use warnings; 

# here's the list of candidate words
my @list = qw(
PARTNERSHIPS
REPRIMANDING
CIVILIZATION
APPRECIATION
CONVERSATION
CIRCUMSTANCE
PURIFICATION
SECLUSIONIST
CONSTRUCTION
DISAPPEARING
TRANSMISSION
APPREHENSIVE
ENCOUNTERING
); # end of the list of words it should be checked against    
# populate two dimensional array with the list,
# so we can compare each letter with the other 
# letters on the same row more easily 
my $list_length = @list;
my @words;

for (my $i = 0; $i < $list_length; $i++) {
    my @letters = split(//, $list[$i]);
    my $letters_length = @letters;
    for (my $j = 0; $j < $letters_length; $j++) {
        $words[$i][$j] = $letters[$j];
    }
}
# this gives a two-dimensional array like this: 
# @words = (    ["B", "A", "K", "E", "R"], 
#               ["S", "A", "L", "E", "R"], 
#               ["B", "A", "L", "E", "R"], 
#               ["C", "A", "R", "E", "R"], 
#               ["R", "U", "F", "F", "R"], 
# ); 
# now, on to find the word with most letters in 
# common with the other on the same row

# add up the score for each letter in each word
my $word_length = @words;
my @letter_score;
for my $i (0 .. $#words) {
    for my $j (0 .. $#{$words[$i]}) {
        for (my $k = 0; $k < $word_length; $k++) {
            if ($words[$i][$j] eq $words[$k][$j]) {
                $letter_score[$i][$j] += 1;    
            }
        }
        $letter_score[$i][$j] -= 1;
    }
}

# sum each score up
my @scores;
for my $i (0 .. $#letter_score ) {
    for my $j (0 .. $#{$letter_score[$i]}) {
        $scores[$i] += $letter_score[$i][$j];
    }
}

# find the highest score
my $max = $scores[0];
foreach my $i (@scores[1 .. $#scores]) {
    if ($i > $max) {
        $max = $i;
    }
}

# and print it all out :D
for my $i (0 .. $#letter_score ) {
    print "$list[$i]: $scores[$i]";
    if ($scores[$i] == $max) {
        print " <- best";
    }     
    print "\n";
}

Creative Commons License

Tester du det første scriptet uten å endre på innholdet, vil du få ut samme ord som i tutorialen til Bosley, nemlig APPRECIATION. I tutorialen kan du se at dette ordet har fire (4) av tolv mulige matches med det virkelige passordet (vist som 4/12 i spillet). Dette er viktig, fordi dette er ting vi må bruke for å korte ned listen av passordkandidater i det andre scriptet.

Det andre scriptet bruker du til å korte ned listen av mulige passordkandidater. Skriv inn ordet du testet på riktig plass, og pass på å få inn matchtallet på riktig plass. Kjør så scriptet fra kommandolinen, slik: perl shortenlist.pl

#!/usr/bin/perl
use strict;
use warnings; 

my $checkword = "APPRECIATION"; # the word to be checked
my $match = 4; # equal to the match you got from testing your checkword
my @checkletters = split(//, $checkword);

# the list of words:
my @wordlist = qw(
PARTNERSHIPS
REPRIMANDING
CIVILIZATION
APPRECIATION
CONVERSATION
CIRCUMSTANCE
PURIFICATION
SECLUSIONIST
CONSTRUCTION
DISAPPEARING
TRANSMISSION
APPREHENSIVE
ENCOUNTERING
); # end of the list of words it should be checked against 
print "$checkword has $match letters in common with:\n";

# split the word into single characters into an array with regexp //
foreach my $word (@wordlist) {
    next if $word eq $checkword;
    my @letters = split(//, $word);
    my $length = @letters; # determine how many letters to check

    my $eq_letters = 0;
    for (my $i = 0; $i < $length; $i++) {
        if ($letters[$i] eq $checkletters[$i]) {
            $eq_letters++;
        }
    }
    if ($eq_letters == $match) {
        print "$word\n";
    }
}

Creative Commons License

Må også rette en stor takk til folkene på Stackoverflow.com som har gitt mye uvurderlig hjelp til prosjektet.