API System
Zo ziet de code van het systeem er ongeveer uit:
API Client:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php
// API Content
if (isset($_POST['username']) && isset($_POST['password'])) {
// Encrypted Post Fields
$username = base64_encode($_POST['username']);
$password = base64_encode(sha1($_POST['password']));
$ip_adress = base64_encode($_SERVER['REMOTE_ADDR']);
// PHP Curl
$ch = curl_init($api_server);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, 'api_key=' . $api_key . '&website=' . $_SERVER['HTTP_HOST'] . '&username=' . $username . '&password=' . $password . '&ip_adress=' . $ip_adress);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$re = curl_exec($ch);
curl_close($ch);
// Handle Data
$api_content = explode('|', $re);
if (empty($api_content[10])) {
echo $re;
} else {
$data1 = $api_content[0];
// enz enz
}
} else {
// Hier het formulier om in te loggen
}
?>
// API Content
if (isset($_POST['username']) && isset($_POST['password'])) {
// Encrypted Post Fields
$username = base64_encode($_POST['username']);
$password = base64_encode(sha1($_POST['password']));
$ip_adress = base64_encode($_SERVER['REMOTE_ADDR']);
// PHP Curl
$ch = curl_init($api_server);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, 'api_key=' . $api_key . '&website=' . $_SERVER['HTTP_HOST'] . '&username=' . $username . '&password=' . $password . '&ip_adress=' . $ip_adress);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$re = curl_exec($ch);
curl_close($ch);
// Handle Data
$api_content = explode('|', $re);
if (empty($api_content[10])) {
echo $re;
} else {
$data1 = $api_content[0];
// enz enz
}
} else {
// Hier het formulier om in te loggen
}
?>
API Server:
De code hiervan komt niet online te staan, hieronder staat informatie die mij belangrijk lijkt om in te schatten of mijn systeem veilig is:
- Iedere query die door de database word uitgevoerd is beveiligd met de volgende functie:
Code (php)
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
<?php
// Mysql Injection
function clean_input($query) {
$query = stripslashes($query);
$query = strip_tags($query);
$query = trim($query);
return mysql_real_escape_string($query);
}
?>
// Mysql Injection
function clean_input($query) {
$query = stripslashes($query);
$query = strip_tags($query);
$query = trim($query);
return mysql_real_escape_string($query);
}
?>
- Het wachtwoord ziet er ongeveer zo uit:
- De API code word gecontroleerd met de database, net zoals die website die gebruikt maakt van de API Client
- De data word uit de database 'ge-echo-ed' (onbeveiligd)
- De server maakt een logbestand met: ip adres gebruiker, ip adres website, api key, query, tijd, datum
Alvast bedankt!
Gewijzigd op 03/02/2011 00:06:30 door Sander de Vos
Ik roep maar wat, maar waarom geen wsdl, soap, xml, json of weetikveelwat?
Maar het voordeel ten opzichte van deze manier daarvan werd me niet echt duidelijk.
Dus heb ik het op deze manier gedaan.
MD5 en veilig/waterdicht? Wat is het punt om geen SHA te gebruiken? En ik neem aan dat je geen SSL gebruikt? In dat geval is spreken van veiligheid/waterdichtheid natuurlijk valse hoop. En het is gewoon een API, geen API System, alhoewel dat wel stoer klinkt natuurlijk. Daarnaast wil ik nog even meegeven dat je foutmeldingen op productie uit moet zetten en dat $_SERVER['REMOTE_ADDR'] door de gebruiker aangepast kan worden. Verder netjes.
The Force op 03/02/2011 01:42:11:
Wat is eigenlijk het verschil tussen MD5 en SHA? Ik heb altijd het idee dat meestal MD5 wordt gebruikt. Maar is dat niet goed dan? En als het niet goed is, waarom gebruikt dan niet iedereen SHA?MD5 en veilig/waterdicht? Wat is het punt om geen SHA te gebruiken?
En waarom zet TS base64_encode op de POST gegevens? Waar dient dat voor?
Met die sha krijg je elke keer een andere waarde.
Het probleem met md5: je kan die md5 waarde Googlen. Als dat een simpel paswoord is (geen camel caps, een bestaand woord, ...), is de kans vrij groot dat je een resultaat vindt.
Dit is me geheel duidelijk, maar dit niet:
"md5 geeft je altijd het zelfde resultaat.
Met die sha krijg je elke keer een andere waarde."
Hoe bedoel je dat je telkens een andere waarde krijgt?
Overigens md5 is 'gemakkelijk' te kraken, er staat zat artikelen op het internet waarin staat hoe je md5 terug kan rekenen. Er is zelf een vrouwtje uit china die het uit haar hoofd kan.
Terugrekenen van md5... tja... dan moet je dus salten... dat kan je toch niet "kraken"? md5(sdfsjfhsh_appel_343334) of is er nog een betere oplossing?
Gewijzigd op 03/02/2011 11:54:39 door Ozzie PHP
Daarom zei ik dus dat ik het betwijfelde.
Precies, een salt gebruiken is gewoon het beste.
en dan wel gewoon md5 gebruiken?
Zou dit geheel veilig zijn stel dat het een wachtwoord was?
md5(sdfsjfhsh_wachtwoord_343334)
Maar dwing gebruikers ook af om 'sterke' wachtwoord te gebruiken.
In plaats van md5 bedoel je? Geen idee... SHA is iets anders weer dan sha1??
In mijn voorbeeld md5(sdfsjfhsh_wachtwoord_343334) is "wachtwoord" het wachtwoord en wat er voor en achter staat de salt & peppa :) Dat is hetzelfde wat jij bedoelt denk ik?
En doe je die salts altijd hetzelfde? Of maak je dat variabel op een of andere manier?
't Is te zeggen: hiermee kan je paswoorden controleren zoals ze in een phpBB3 forum gecodeerd zijn.
Ik heb dit zelf niet geschreven, er staat een referentie bij.
Zoals je ziet: verschillende waarden die in de database kunnen staan geven je toch een true (of false als je $val_post aanpast)
Wat phpBB doet, is telkens bij het inloggen een andere waarde ( phpbb_hash($_POST['paswoord']) ) in de db opslaan.
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
<?php
$val_database =phpbb_hash('admin123');
// stel: $val_database is nu de waarde zoals ze in de db staat.
$val_post = "admin123";
// zoals je ze uit $_POST haalt
if(phpbb_check_hash(
$val_post,
$val_database
)
) {
echo "Value is true";
}
else {
echo "val is false";
}
echo '<p>wachtwoord in database: '. $val_database .'</p>';
////////////////////////////////////////////////////////////////////////
/**
* slightly adapted from @see http://lifekamazza.blogspot.com/2007/10/hack-password-encryption-in-phpbb3.html
*/
function phpbb_hash($password) {
$itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
$random_state = unique_id();
$random = '';
$count = 6;
if (($fh = @fopen('/dev/urandom', 'rb'))) {
$random = fread($fh, $count);
fclose($fh);
}
if (strlen($random) < $count) {
$random = '';
for ($i = 0; $i < $count; $i += 16) {
$random_state = md5(unique_id() . $random_state);
$random .= pack('H*', md5($random_state));
}
$random = substr($random, 0, $count);
}
$hash = _hash_crypt_private($password, _hash_gensalt_private($random, $itoa64), $itoa64);
if (strlen($hash) == 34) {
return $hash;
}
return md5($password);
}
function unique_id($extra = 'c') {
static $dss_seeded = false;
global $config;
$val = $config['rand_seed'] . microtime();
$val = md5($val);
$config['rand_seed'] = md5($config['rand_seed'] . $val . $extra);
if ($dss_seeded !== true && ($config['rand_seed_last_update'] < time() - rand(1,10))) {
$config['rand_seed_last_update']=time();
$dss_seeded = true;
}
return substr($val, 4, 16);
}
function _hash_crypt_private($password, $setting, &$itoa64) {
$output = '*';
// Check for correct hash
if (substr($setting, 0, 3) != '$H$') {
return $output;
}
$count_log2 = strpos($itoa64, $setting[3]);
if ($count_log2 < 7 || $count_log2 > 30) {
return $output;
}
$count = 1 << $count_log2;
$salt = substr($setting, 4, 8);
if (strlen($salt) != 8) {
return $output;
}
/**
* We're kind of forced to use MD5 here since it's the only
* cryptographic primitive available in all versions of PHP
* currently in use. To implement our own low-level crypto
* in PHP would result in much worse performance and
* consequently in lower iteration counts and hashes that are
* quicker to crack (by non-PHP code).
*/
$hash = pack('H*', md5($salt . $password));
do {
$hash = pack('H*', md5($hash . $password));
} while (--$count);
$output = substr($setting, 0, 12);
$output .= _hash_encode64($hash, 16, $itoa64);
return $output;
}
function _hash_gensalt_private($input, &$itoa64, $iteration_count_log2 = 6) {
if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31) {
$iteration_count_log2 = 8;
}
$output = '$H$';
$output .= $itoa64[min($iteration_count_log2 + ((PHP_VERSION >= 5) ? 5 : 3), 30)];
$output .= _hash_encode64($input, 6, $itoa64);
return $output;
}
/**
* Encode hash
*/
function _hash_encode64($input, $count, &$itoa64) {
$output = '';
$i = 0;
do {
$value = ord($input[$i++]);
$output .= $itoa64[$value & 0x3f];
if ($i < $count) {
$value |= ord($input[$i]) << 8;
}
$output .= $itoa64[($value >> 6) & 0x3f];
if ($i++ >= $count) {
break;
}
if ($i < $count) {
$value |= ord($input[$i]) << 16;
}
$output .= $itoa64[($value >> 12) & 0x3f];
if ($i++ >= $count) {
break;
}
$output .= $itoa64[($value >> 18) & 0x3f];
} while ($i < $count);
return $output;
}
function phpbb_check_hash($password, $hash) {
$itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
if (strlen($hash) == 34) {
return (_hash_crypt_private($password, $hash, $itoa64) === $hash) ? true : false;
}
return (md5($password) === $hash) ? true : false;
}
?>
$val_database =phpbb_hash('admin123');
// stel: $val_database is nu de waarde zoals ze in de db staat.
$val_post = "admin123";
// zoals je ze uit $_POST haalt
if(phpbb_check_hash(
$val_post,
$val_database
)
) {
echo "Value is true";
}
else {
echo "val is false";
}
echo '<p>wachtwoord in database: '. $val_database .'</p>';
////////////////////////////////////////////////////////////////////////
/**
* slightly adapted from @see http://lifekamazza.blogspot.com/2007/10/hack-password-encryption-in-phpbb3.html
*/
function phpbb_hash($password) {
$itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
$random_state = unique_id();
$random = '';
$count = 6;
if (($fh = @fopen('/dev/urandom', 'rb'))) {
$random = fread($fh, $count);
fclose($fh);
}
if (strlen($random) < $count) {
$random = '';
for ($i = 0; $i < $count; $i += 16) {
$random_state = md5(unique_id() . $random_state);
$random .= pack('H*', md5($random_state));
}
$random = substr($random, 0, $count);
}
$hash = _hash_crypt_private($password, _hash_gensalt_private($random, $itoa64), $itoa64);
if (strlen($hash) == 34) {
return $hash;
}
return md5($password);
}
function unique_id($extra = 'c') {
static $dss_seeded = false;
global $config;
$val = $config['rand_seed'] . microtime();
$val = md5($val);
$config['rand_seed'] = md5($config['rand_seed'] . $val . $extra);
if ($dss_seeded !== true && ($config['rand_seed_last_update'] < time() - rand(1,10))) {
$config['rand_seed_last_update']=time();
$dss_seeded = true;
}
return substr($val, 4, 16);
}
function _hash_crypt_private($password, $setting, &$itoa64) {
$output = '*';
// Check for correct hash
if (substr($setting, 0, 3) != '$H$') {
return $output;
}
$count_log2 = strpos($itoa64, $setting[3]);
if ($count_log2 < 7 || $count_log2 > 30) {
return $output;
}
$count = 1 << $count_log2;
$salt = substr($setting, 4, 8);
if (strlen($salt) != 8) {
return $output;
}
/**
* We're kind of forced to use MD5 here since it's the only
* cryptographic primitive available in all versions of PHP
* currently in use. To implement our own low-level crypto
* in PHP would result in much worse performance and
* consequently in lower iteration counts and hashes that are
* quicker to crack (by non-PHP code).
*/
$hash = pack('H*', md5($salt . $password));
do {
$hash = pack('H*', md5($hash . $password));
} while (--$count);
$output = substr($setting, 0, 12);
$output .= _hash_encode64($hash, 16, $itoa64);
return $output;
}
function _hash_gensalt_private($input, &$itoa64, $iteration_count_log2 = 6) {
if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31) {
$iteration_count_log2 = 8;
}
$output = '$H$';
$output .= $itoa64[min($iteration_count_log2 + ((PHP_VERSION >= 5) ? 5 : 3), 30)];
$output .= _hash_encode64($input, 6, $itoa64);
return $output;
}
/**
* Encode hash
*/
function _hash_encode64($input, $count, &$itoa64) {
$output = '';
$i = 0;
do {
$value = ord($input[$i++]);
$output .= $itoa64[$value & 0x3f];
if ($i < $count) {
$value |= ord($input[$i]) << 8;
}
$output .= $itoa64[($value >> 6) & 0x3f];
if ($i++ >= $count) {
break;
}
if ($i < $count) {
$value |= ord($input[$i]) << 16;
}
$output .= $itoa64[($value >> 12) & 0x3f];
if ($i++ >= $count) {
break;
}
$output .= $itoa64[($value >> 18) & 0x3f];
} while ($i < $count);
return $output;
}
function phpbb_check_hash($password, $hash) {
$itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
if (strlen($hash) == 34) {
return (_hash_crypt_private($password, $hash, $itoa64) === $hash) ? true : false;
}
return (md5($password) === $hash) ? true : false;
}
?>
Ik snap niet hoe het werkt hoor... en wat je nou precies bedoelt. Kun je een voorbeeldje geven in woorden van wat er gebeurt?
Zie dat je een gecodeerd paswoord kan kopiëren uit een db, voor een phpBB3 forum.
(Desnoods zwier je ergens een phpbb3 forum ergens online, ... zie in de users tabel ...)
test dan dit uit
Code (php)
1
2
3
4
5
6
2
3
4
5
6
<?php
echo phpbb_check_hash(
$ongecodeerd_paswoord,
$waarde_zoals_ze_in_de_db_staat
);
?>
echo phpbb_check_hash(
$ongecodeerd_paswoord,
$waarde_zoals_ze_in_de_db_staat
);
?>
(zie dat je de functies ook ergens zet, uiteraard)
Gewijzigd op 03/02/2011 13:46:31 door Kris Peeters
Misschien is er iemand anders die snapt wat Kris wil zeggen, maar die het op een adere manier kan verwoorden...
Als ik het goed begrijp moet dit dus nog gebeuren:
- SSL Verbinding (word al geregeld)
- Een betere manier van wachtwoorden opslaan (md5(sha1($_POST['password']) . $salt);) ??)
- Een alternatief voor $_SERVER['REMOTE_ADDR']
De data word nu zonder encryptie weergeven en opgehaald via de client, is dit veilig, of moet ik hier nog een encryptie op zetten. Zo ja, welke?
doe maar gewoon sha(post.salt).
Maar hebben jullie ook nog ideeën voor de andere 'problemen'?
En is mijn clean_iput functie goed (genoeg).
Bevat hij onnodige dingen, of mist hij iets enz.
Alvast bedankt!
Gewijzigd op 14/02/2011 23:17:17 door Sander de Vos