Comparing user-input CAPTCHA value against expected value stored in session - php

I'm trying to implement a simple captcha into a form I'm building but I've run up against an issue I can't seem to sort out by myself.
I'm using simple code to generate a random number like so ....
$randomnr = rand(1000, 9999);
$_SESSION['randomnr2'] = md5($randomnr);
.... and then some more code to generate an image of the random number and display it on the page. I'm against it for validity like this ....
if (strlen($captcha) !== ($_SESSION['randomnr2'])) {
$error['captcha'] = "CAPTCHA error. Please try again";
}
How do I go about checking the value that's been input into the captcha input field against the random number that's stored in the session randomnr2?

I'm not sure why you are checking the length of the string against an md5 hash of the string here, but assuming $captcha is the number from the user, you can just do this:
if(md5($captcha) !== $_SESSION['randomnr2']) {
$error['captcha'] = "CAPTCHA error. Please try again";
}

PHP will auto-convert anything to a string (if it can) for strlen(), so
echo strlen(42);
echo strlen('42');
will both output '2', even though the first one's an integer. To compare the submitted value to the store value, it's as simple as
if ($_SESSION['randomnr2'] === (int)$captcha) {
... it matched ...
}
You'll want to cast the submitted value to an int again, as anything in the PHP $_GET/POST arrays is internally treated as a string.

<div id='captcha_to_show' style='border:1px solid silver;'>gobldeygook</div>
<input name='captcha' id='captcha'>
...
attached via scriptmonkey...
$('document').ready(function(){
$('#captcha').val($('#captcha_to_show').html());
});
look into a open-source captcha script. your implementation is going to require sending that captcha across the page in a way that it's value can be seen by whatever is pulling the page, and that person/bot/whatever can fill in the validating field accordingly, so you actually have zero protection. that is why captchas either use convoluted images that are hard to impossible to read with a script, or semantic questions better understood by humans in context than bots, such as ['What would you say the sum of one and 3 are?' === 4]. and yes, the more simple image captcha's with the set fonts, spacing and size can be hacked with a sort of pixel-pattern dictionary attack.

Related

Is possible to find a string that satisfy this condition?

$myStr = $_GET['myStr'];
if ($myStr == md5($myStr)) echo "ok\n";
I know there is a type jugglying in the code, but in my tests I couldn't find an input that satisfies the condition.
No, you cannot find that myStr value as it would come down to finding a (first degree) pre-image for MD5. Although MD5 has been broken for collision resistance, you should not be able to find a pre-image. More information here.
I'm presuming there that your code amounts to finding y = md5(y). y = md5(x) is a more general assumption and it is described in the Wikipedia article linked to above that it is impossible to find such H(x), even for MD5.
That doesn't mean that you should use MD5. Please use SHA-256, SHA-512 or indeed one of the SHA-3 functions. Even if MD5 hasn't been broken that far, it has been broken enough not to be used anymore; "Attacks always get better; they never get worse."
Let's start from the beginning. I will provide an example so i may help you maybe understand better.
In the first line you have $myStr = $_GET['myStr'];
I will just assume you will get this variable from your url like this :
http://localhost/md5Project.php?myStr=test
This will give your variable $myStr the value "test".
Moving forward in your if statement you have:
if ($myStr == md5($myStr)
this will never be true because $myStr value is "test" and md5($myStr) value is 098f6bcd4621d373cade4e832627b4f6 so basically you compare 2 strings with values "test" and "098f6bcd4621d373cade4e832627b4f6problem" which will always lead to false.

Best way for unique id (PHP + Mysql)

I have a file sharing website, and every file has a random id. Example for an id: G4t68MgW7
Every upload I create a random id, and check if it's exists (in a loop). There are some issues with that way.
I have to check if this id does exists (Mysql query)
It's a limited range
So how can I can create a unique id without limitation and without checking if it already exists?
Note: I don't use Auto Increment because I want to avoid from bots to reach every file in my website. example of how it looks in the browser: http://www.example.com/file/G4t68MgW7
You can assign timestamp value ie, time() as id. It will be unique always
Well, you more or less gave the answer yourself.
Illustrated with the following pseudocode:
while (true) {
hash = generate_hash();
SQL -> Check if hash found
if (!found) {
break;
}
}
It is pretty easy to implement this. The generate hash could be a simple md5 or it could be a function that builds a random string based on an array of letters. For example something as simple as:
function generate_hash() {
return '$2y$' . substr(md5(time() . 'foo' . rand(0, 1000000) . 'bar'), 0, 15) . 'ydfdf';
}
In 99.999% of all cases, the hash would be unique, so performance should not be an issue here. This also creates more "randomness" than uniqid().
echo substr(uniqid(rand(10,1000),false),rand(0,10),6)
You can have a table of pre-defined identifiers, so you make sure that they are unique in creation time (you don't have to query if they exist; simply insert and don't do anything if the insert fails). When you want a file to be uploaded, get an unused code and mark it as used so it's not used again.
You can also have a cron to check if you're running out of codes, and run the generation script again (increasing the number of characters makes the number of codes virtually unlimited). As this is asynchronous, it won't affect performance.

Questions on how to generate unique key code programeatically for each project?

I want to generate a Unique Code for each project being created. I have an HTML5 webpage that allows user to create new project, each project when created successfully be assigned a unique code.
I am making a Ajax call to the PHP file on the web server which in-turns saves the project details in MySql database. I have a column in the table that stores unique code for each project created.
I am confused how do i create this code ? is it in PHP or shall i do it in MySql. I want it to be a unique code which will be used by the client to distribute to their customers.
I haven't decided on the length of the key yet but it should be around 8 Digits(combination of char & int is fine ). I know i could use HashTable in Java to create this code based on the inputs from user but i am a fresher to PHP/MySql.
Any advise ?
Note: My Aim is that the key should not be repeated
You can use PHP's uniqid() to generate a unique ID. However, this should not be used for security purposes, as explicity stated in the PHP manual. For more info, go here
Example:
$unique_key = uniqid();
echo $unique_key; // Outputs unique alphanumeric key, like 5369adb278516
Generate Code:
// $length is the length of code you want to return
function generate_code($length) {
$charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789012345678900987654321234567890";
return substr(str_shuffle($charset), 0, $length);
}
To get the verification code, it will call user_code_exists() with a parameter of the generated code which is on $code = generate_code(50).
It will check the database if there's at least one row that has the same value, if the row is 0 (code doesn't exist) it will return as true.
// Do generate and verify code existence
$verification_code = "";
while($this->user_code_exists($code = generate_code(50)) == true) {
$verification_code = $code;
break;
}
public function user_code_exists($code) {
$query = $this->db->prepare("SELECT verification_code FROM accounts WHERE verification_code = :verification_code");
$query->execute(array(':verification_code' => $code));
return ($query->rowCount() == 0) ? true : false;
}
On while loop, once it returns true, the variable $verification_code holds the unique generated code.
This is just an overview, I hope this helps.
See the answers given for this question:
What is the best way to create a random hash/string?
In particular, if you want a purely random value (as opposed to, say a hash of the project name) then see the answer by #Gajus Kuizinas, except using base64_encode rather than binhex will give a shorter but still readable value:
base64_encode(mcrypt_create_iv(8, MCRYPT_DEV_URANDOM));
will give you 11 characters: NTM2OWI0YzR
Or if you don't have the mcrypt library installed, try:
base64_encode(hex2bin(uniqid()."0")); // Derived from microtime (the "0" is needed since uniqid() gives an odd number of characters
gives 10 characters: U2m5vF8FAA after discarding the trailing '=='
If you want to be paranoid about the project code never repeating, add a unique index to the column in your MySql table that stores the unique code for each project created, and repeat the number generation if your insert into the table fails.
As noted by #Mark M above, if you are concerned about security or someone masquerading an existing project code, see #Anthony Forloney's answer in the related question link above. In particular:
Numbers used once (NONCE) - They are used on requests to prevent
unauthorized access, they send a secret key and check the key each
time your code is used.
You can check out more at PHP NONCE Library from FullThrottle
Development
I needed to do something similar, a solution to keep unique id and i ended up with a solution to use PHP function time() like this $reference_number = 'BFF-' . time(); you can change the BFF to something that makes more sense to your business logic. This way i dont have to worry about if new id that is being generated was taken up before.
I hope this helps

Sending Random numbers to a database as it's ID

I'm trying to send a random number to the database for a user/article ID. It is currently using auto increment as a counting system. However, I'd like for the number to be random and unpredictable.
The mt_rand() function in PHP does exactly what I need. Although, my question is what happens when the function returns a number already in use. Of course I can just use a is_null() to check. But if it keeps on picking a number in use I could imagine that that'd slow the operation down.
Any thoughts on what I might be able to do to get around this? Perhaps I'm going at this all wrong.
Also if there's a function that gives letters and numbers that would also help greatly (like Youtube's).
Thanks for reading!
Here is a simple function to create a 10 character long string. The string is built using upper/lowercase text and numbers. Auto increment is definitely the way to go, however, if you are dead set, the function below should help.
<?php
function randomID()
{
$ID = substr(str_shuffle(str_repeat('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',5)),0,10);
echo $ID;
}
randomID();
?>
To make the string longer, change 10 to whatever you like. In terms of ensuring it does not already exist. I would suggest you generate the new ID and then do a search in the database to ensure it does not exist before inserting. Granted this is an extra step in the chain, but unfortunately this is what needs to be done.
Hope this helps
You should always use an auto_increment field as the primary key of your database. Not doing that costs you a great deal in performance. You can certainly create a secondary ID field with your random ID. I'd probably use a hashing function to get the best chance of a random string:
<?php $key = md5(rand(0,999).time().$myItemTitle); // ex. ce4075a3d3f6fd757eb6dd44810cbe14
You should always (in normal use cases) use an auto incremented ID for performance reasons. If you're purpose is to be able to somewhat hide the next post because someone could be guessing for it then you better add some kind of hashed unique field to your database.
Always random (just encrypting ms) :
<?php
$value = time();
$key = "543yretghf436436";
$encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $value, MCRYPT_MODE_ECB);
//if you want even long string change 128 to 256
$encrypted = base64_encode($encrypted);
$encrypted = rtrim($encrypted, '=');
echo $encrypted;
?>
e.g.
Egttu2XhRGdAiXVfszscWg
XlttfR3XaL6pym1uSNY7Kg
YvoKCweUnN8gZyodRYysLA
What you actually want is some "random" key to use as an identifier for the article. I would keep the auto_increment and eigther:
add an column with a "hashkey" or "random key" to identify the article. This poses the "i already have this key" issue (which should not be that large unless you have billions of articles). See some code examples already posted.
create an extra table with pregenerated keys (i.e. 10000 id -> key values) where you can lookup the id by key. If the table runs out you can easily generate new values. This way you don't have to worry about getting "slow" generation speed.

Masking URL parameters

I often want to redirect the user or email them a link but I want to mask the parameters in the URL so they can't tell what extra information is being sent.
For example, if I want to present a link to http://www.example.com/directory/ but I also want to pass extra parameters of an email address and a hash for someone:
Email: someone#example.com
Hash: 22sd359d5823ddg4653dfgfFSG2
I can send them to this link, but I don't want them to see the parameters:
http://www.example.com/directory/someone%40example.com/22sd359d5823ddg4653dfgfFSG2
So my first thought is just to base64_encode() it, but then you get those stupid == symbols at the end for the extra bytes. And also base64 encoding also generates quite long strings.
Is there an easier, URL-friendly way to encode a string to hide its contents?
How would you normally do this? Is base64_encode() a standard practice?
You could generate a short id and store what it's suppose to do in the database. So using
http://www.example.com/directory/K2SP26
for example would store the person's email address in the database along with where they are supposed to go. Check out http://kevin.vanzonneveld.net/techblog/article/create_short_ids_with_php_like_youtube_or_tinyurl/
Using something like base64_encode(), gzcompress, etc. to encode the string isn't a good way to obfuscate it since it's trivial to decode it. And yes, another option is to store the value in the database and just pass a key as people have suggested. But assuming you don't want to bother with that, what you really should do is to actually encrypt it using a private key, and then decrypt it on the other end with the same key.
For example:
function obfuscateString($s)
{
$secretHash = "BA2EC9E717B68176902FF355C23DB6D10D421F93EAF9EE8E74C374A7B0588461";
return openssl_encrypt($s, 'AES-256-CBC', $secretHash, 0, '1234567890123456');
}
function unobfuscateString($s)
{
$secretHash = "BA2EC9E717B68176902FF355C23DB6D10D421F93EAF9EE8E74C374A7B0588461";
return openssl_decrypt($s, 'AES-256-CBC', $secretHash, 0, '1234567890123456');
}
(Requires PHP version >= 5.3.0.) Replace the $secretHash with your own secret hex string.
Note: The initialization vector ('1234567890123456') is just a filler string in this example, but that's ok. You could come up with a way to use a unique initialization vector, but it isn't important for the purposes of obfuscating the URL parameters in most cases.
Probably a silly answer but why not use the mcrypt functions to hide your parameters from at least the more casual users?
If your redirect is triggered by PHP, I suppose storing the data in a session would be the obvious choice.
<?php
function redirectTo($url, $data) {
session_start();
$hash = md5(uniqid("rediredt", true));
$_SESSION[$hash] = array(
'my' => 'data',
'is' => 'invisible',
'to' => 'the user',
);
$delim = strpos($url, '?') ? '&' : '?';
$url .= $delim . 'redirection-key=' . $hash;
// might want to send 301 / 302 header…
header('Location: ' . $url);
exit; // might want to avoid exit if you're running fcgid or similar
}
function isRedirected() {
if (empty($_GET['redirection-key'])) {
return null;
}
if (!isset($_SESSION[$_GET['redirection-key']])) {
return array();
}
$t = $_SESSION[$_GET['redirection-key']];
unset($_SESSION[$_GET['redirection-key']]);
return $t;
}
might help you grasp the idea…
You have one of two choices:
The email address is hashed, and can therefore be decoded by a savy user.
-or-
The email address is stored on your server (database) and the email link contains only the database primary ID.
If you want the most secure method, that also gives the prettiest URLs, use method 2. If you absolutely do not want to store the email address in your database, then either use a common hash, such as base64 or even rot13, or roll your own. You will find that rolling your own is not simply, but it will stop most casual users from trying to peek inside the hash.
Its a bit hacky, but if you send them a page containing:
<form id="getme" action="directory/someone" method="POST">
<input type="hidden" name="email" value="someone#example.com">
</form>
<script> document.getElementById("getme").sumbit();</script>
As soon as that loads (assuming they have javascript enabled), they will be redirected where you want them with no url dirtyness.

Categories