PHP: Detect password parameter in string and replace with default text - php

I have an api logging system which records logins but I do not want to store passwords in the logs.
This is an example of a request string to the log:
NOTE: the string will not be exactly the same and will contain parameters in different order, so I am thinking maybe someREGEX can handle this?
api.my.geatapim/live/?action=login_user&username=joe#bloggs.com&password=PassWord&session_length=10080
What I need to do, is:
Detect if the parameter "password=" is in the string
If its in the string replace the password part with OBFUSCATED so result will be:
api.my.geatapim/live/?action=login_user&username=joe#bloggs.com&password=OBFUSCATED&session_length=10080
I have tried this but does not work: $request_string = preg_replace("/password=\d+/", "password=OBFUSCATED", $request_string);

The Expression
\d+ is for digits ([0-9]). You'll want to include more character sets for the password, considering the one you provided is using [A-Za-z].
$request_string = preg_replace("/password=\w+/", "password=OBFUSCATED", $request_string);
Though, considering a typical password will have a bigger character set than [a-zA-Z0-9_], taking into account special characters (but since it's in a URL, it'll possibly be urlencoded()'d. For example, P&ssW0rd! will become P%26ssW0rd!.)
$request_string = preg_replace("/password=[^&]+/", "password=OBFUSCATED", $request_string);
"I do not want to store passwords in the logs."
This logic won't modify what is put into your Apache/Nginx/Whatever access_log (unless you write these logs to /dev/null or another void place). You can also not write the passwords in the logs if you change it from a HTTP GET to a HTTP POST (or HTTP PUT) and have the credentials in the body, or, use HTTP Authentication headers.
Although your question is quite easy to solve, it has nothing to do with your actual problem. you simply should never transfer password data via $_GET - it's one of the big no no-s of handling credentials. — Franz Gleichmann

Try this code, it works
<?php
$request_string = "api.my.geatapim/live/?action=login_user&username=joe#bloggs.com&password=PassWord&session_length=10080";
echo $request_string = preg_replace("/password=\w+/", "password=OBFUSCATED", $request_string);
?>
Output : api.my.geatapim/live/?action=login_user&username=joe#bloggs.com&password=OBFUSCATED&session_length=10080

Related

Issue with encoding on receiver end when using xmlrpc_encode_request

I have an issue with charsets and how they are encoded in a request I send. I have a test case where I want the code to end up with the exact same md5-hash on both sides. While still being the character 'å', obviously. (So not converted into some broken char or just '?')
The source input is utf8 and contains a norwegian character, for example "båt".
This input will then be sent to an API that wants data to be latin1 / ISO-8859-1.
One goal is also to avoid having to add utf8_decode to the receiving end.
So this is the very simplified code of what I've sent until now:
$password_send = 'båt';
echo "Test 1: " . md5( $password ) . "\n";
$params = array('password' => $password);
$request = xmlrpc_encode_request($module, $params);
And this is how the receiving end treats it. It basically just converts it into an md5 hash and sends it to another method. No other conversion of the incoming data has been done.
$_hash = md5( $password_receive );
echo "Test 2: {$_hash}\n";
Member::updatePassword($member_id, $_hash);
I need the $_hash to be (when 'båt' is sent) to end up as the hash 7e2cdd98fccee62723784a815a2ecdcb. Since this is the md5-hash that 'båt' resolves into when the password 'båt' is saved on the site itself (and not trough the API)
So when I send 'båt' in the API-request, then on the receiver end, it ends up with: fd9cac747daca144726dc579c32f48a, which is wrong. When I check the md5() of 'båt' before I send it, then it is also displayed as fd9cac747daca144726dc579c32f48ae.
I guess this is expected, since I don't use utf8_decode yet, but if I change what I send, like so: $password_send = utf8_decode('båt');
Then it still doesn't end up with the correct hash on the receiver end, then it ends up with: b865deb1e3b0891a41c5444c00893a0f
However, if I also add utf8_decode on the receiver end, like so: $_hash = utf8_decode($password_receive), then it ends up with the hash I need it to be: 7e2cdd98fccee62723784a815a2ecdcb
But this seems very wrong... Having to do utf8_decode on both sides. And while this hash is now correct on the receiving end too, the issue is that I don't want to change any code on the receiving end. And it doesn't work to just do utf8_decode twice before I send the value, because then I just end up with the hash c2d1fbc45e123f65edd74401ef58dd6a on the receiving end (which is the equivalent of doing md5('b?t'). It only worked when I do utf8_decode once before I send it, and once on the receiver end.
So I started to realize that xmlrpc_encode_request probably is the culprit, in that it maybe did some conversion on it's own. First I checked what a var_dump of $request said, in the cases where the $password_send value has NOT been utf8_decoded. And that is:
<string>båt</string>
When I do utf8_decode on the value $password_send before it's made into an xmlrpc request, then it is:
<string>båt</string>
Then I read the documentation on xmlrpc_encode_request. And I've tried various combinations of output_options, but none of them seems to work. In every scenario I still have to do utf8_decode in the code on the input data on the receiver end to end up with the exact same md5 that I need.
I realize this might be somewhat confusing. I would really really appreciate it if someone is able to help me out here. By giving me some pointer on what I should do or try. Because I've gotten completely lost on this issue now :(
The problem seems to be the escaping of xmlrpc_encode_request function. I have same problem albeit with czech "ě" character. I believe it might be bug in PHP, I however found a simple workaround.
Just turn of escaping of non-print and non-ascii characters.
echo xmlrpc_encode_request('test', 'å'); //Ã¥ - incorrect
echo xmlrpc_encode_request('test', 'å', ['escaping' => 'markup']); //å - correct

PHP comment character escaping

I made a .htaccess file that redirects, for example, link:
website.com/module#controller
to:
website.com/?url=module#controller
As # is the PHP comment declarer, I get a problem when need to load:
$bootstrap->init($url) // $url = module#controller;
I tried to use addslashees($url);, but still when I:
echo $url;
I still get an output of:
module
How I should clear that string, to treat the # sign as part of the string?
$url = module#controller; is not valid PHP.
$url = 'module#controller'; will (correctly) not treat the # as a comment initiator.
Additionally, a # in a URL isn't going to work the way you expect. That's the marker for the URL hash/anchor, which is not passed to the web server. This is likely why you get output of module - your problem is at the browser level, not PHP.
The hashtag fragment identifier is a client-side concept only. The browser would never send a hashtag value to the server.
If you are relying on this functionality, your are going to be disappointed as server has absolutely no way to do redirection based on the hashtag, as it never even sees the hashtag.

Codeigniter trying to send HTML content via ajax?

I'm trying send an HTML string from the client to the server via ajax. I keep getting "disallowed key characters" error. So I took this $config['permitted_uri_chars'] = 'a-z 0-9~%.:_\-'; and set it to nothing $config['permitted_uri_chars'] = ''; Since CodeIgniter says Leave blank to allow all characters -- but only if you are insane. But I still get Disallowed Key Characters error.
This is how I'm trying to send it:
var content = '<p class="MsoNormal">Hi {$first_name}</p>\n<p class="MsoNormal">My name is Bill, etc etc.</p>';
$.get('/task/preview_template', {content:content}, function(data) {
console.log(data); //Disallowed Key Characters
});
_clean_input_keys is your likely culprit for what's throwing the error, and you have a large number of characters that fall outside of the allowed characters of "/^[a-z0-9:_\/-]+$/i".
There are a few ways that I can think of that might handle this:
Modify _clean_input_keys so that it accepts the extra characters. This, of course, is an internal function for a reason and shouldn't be changed unless you know what you're doing. (Alternatively, you may be able to modify it to allow the special characters for HTML encoding and HTML encode the string. This helps mitigate the compromise to security that comes with adding such characters to _clean_input_keys.)
Encode your string before sending it, then decode it on the server side. This is a little more work on both your part, and that of the computers involved, but it keeps _clean_input_keys intact, and should allow you to send your string up, if you can find an encoding that is reliable in both directions and doesn't produce any disallowed characters. Since you're using GET, you may also run into GET input limits on not only the server, but browser-side, as well.
Use POST instead of GET and send your content as a data object. Then just use the $_POST variable on the server, instead of $_GET. While this may work, it is a bit unorthodox and nonstandard usage of the REST verbs.
Store your template content on the server, and reference it by name, instead of storing it in the JavaScript. This, of course, only works if you're not generating your template content on the fly in the JavaScript. If you're using the same template(s) in all of your JavaScript calls, though, then there's really no reason to send that information from JavaScript to begin with.

Cookies with extensions

I've seen cookies set by web pages with the "." character in them. I'm trying to maximize the dynamic use of a $_GET['url'] to set my cookies, and then include it in a next page as a conditional where it checks to make sure the cookie was set before it allows users to perform an action. Basically I'm using cookies and IP addresses in an anonymous voting action to make sure anyone who votes only gets one per day. IPs are reset through a cron job once a day, and the cookies are set to expire after 17 hours. I have no issues setting a cookie named with the .php extension, however after many hours of trial and error, I can't get it to accept it in an if(isset). No matter what I try, it will not recognize that the cookie is set. Without the extension everything works fine. I've tried a dozen configurations, but here's basically what I have trying to debug.
<?php
$cookie = "test.php";
setcookie("$cookie", "workdamnyou");
if (isset($_COOKIE[$cookie])) {
echo "is set";
}
else {
echo "not set";
}
?>
I've tried isset($_COOKIE["$cookie"]) and isset($COOKIE['$cookie']) as well. That said, I really wish you could run PHP without uploading it each time to your server.. --
setcookie doesn't change $_COOKIE immediately. It sets the headers to change the cookie in the browser, so the script won't see the test value until you refresh the page.
You CAN run PHP without uploading to a server; the easiest option is to install a xAMP stack (LAMP/MAMP/WAMP depending on if you're developing on Linux/Mac/Windows).
Well, I found the solution I guess... PHP doesn't like dots in variable names (http://www.php.net/manual/en/language.variables.basics.php). Now, since Register Globals could be on, it might be possible that a $_COOKIE["name.ext"] could turn into a $name.ext which would be invalid. Thus, "Dots and spaces in variable names are converted to underscores. For example becomes $_REQUEST["a_b"]." (http://www.php.net/manual/en/language.variables.external.php). Does a check for isset("name_php") work?
You cannot set and access a cookie in the same instance! You have to do a redirect, refresh or something, but you cannot both set and access at the same time. Also make sure your other parameters are set like hostname, expiry time. . e.t.c
Eg.
setcookie("TestCookie", $value, time()+3600, "/", "/", 1);
For debugging, just do a var_dump($_COOKIE)
Note that cookies only become available on the next pageload (when they have traversed from server to client and back).
Try setting the cookie directly with $_COOKIES["test.php"] = "test"; and see what happens with
var_dump($_COOKIE);
Also don't use the quotes around the $cookie variable. Thus make it
setcookie($cookie, "work");
instead of
setcookie("$cookie", "work");
Last, you can run PHP locally with your own server. The easiest way on Windows is the WAMPP stack. I find this one very easy to install and run: http://www.apachefriends.org/en/xampp.html
Good luck!
Why would you have a .php extension in the cookie name? It should be:
$cookie = 'test';
See http://www.ietf.org/rfc/rfc2109.txt point 4.1:
The two state management headers, Set-Cookie and Cookie, have common
syntactic properties involving attribute-value pairs. The
following grammar uses the notation, and tokens DIGIT (decimal
digits) and token (informally, a sequence of non-special, non-white
space characters) from the HTTP/1.1 specification [RFC 2068] to
describe their syntax.
av-pairs = av-pair *(";" av-pair)
av-pair = attr ["=" value] ; optional value
attr = token
value = word
word = token | quoted-string
Attributes (names) (attr) are case-insensitive. White space is
permitted between tokens. Note that while the above syntax
description shows value as optional, most attrs require them.
NOTE: The syntax above allows whitespace between the attribute and
the = sign.

using a base64 encoded string in url with codeigniter

I have an encrypted, base64 encoded array that I need to put into a url and insert into emails we send to clients to enable them to be identified (uniquely) - the problem is that base64_encode() often appends an = symbol or two after it's string of characters, which by default is disallowed by CI.
Here's an example:
http://example.com/cec/pay_invoice/VXpkUmJnMWxYRFZWTEZSd0RXZFRaMVZnQWowR2N3TTdEVzRDZGdCbkQycFFaZ0JpQmd4V09RRmdWbkVMYXdZbUJ6OEdZQVJ1QlNJTU9Bb3RWenNFSmxaaFVXcFZaMXQxQXpWV1BRQThVVEpUT0ZFZ0RRbGNabFV6VkNFTlpsTWxWV29DTmdackEzQU5Nd0lpQURNUGNGQS9BRFlHWTFacUFTWldOZ3M5QmpRSGJBWTlCREVGWkF4V0NtQlhiZ1IzVm1CUk9sVm5XMllEWlZaaEFHeFJZMU51VVdNTmJsdzNWVzlVT0EwZw==
Now I understand I can allow the = sign in config.php, but I don't fully understand the security implications in doing so (it must have been disabled for a reason right?)
Does anyone know why it might be a bad idea to allow the = symbol in URLs?
Thanks!
John.
Not sure why = is disallowed, but you could also leave off the equals signs.
$base_64 = base64_encode($data);
$url_param = rtrim($base_64, '=');
// and later:
$base_64 = $url_param . str_repeat('=', strlen($url_param) % 4);
$data = base64_decode($base_64);
The base64 spec only allows = signs at the end of the string, and they are used purely as padding, there is no chance of data loss.
Edit: It's possible that it doesn't allow this as a compatibility option. There's no reason that I can think of from a security perspective, but there's a possibility that it may mess with query string parsing somewhere in the tool chain.
Please add the character "=" to $config['permitted_uri_chars'] in your config.php file you can find that file at application/config folder
Originally there are no any harmful characters in the url at all. But there are not experienced developers or bad-written software that helps some characters to become evil.
As of = - I don't see any issues with using it in urls
Instead of updating config file you can use urlencode and urldecode function of native php.
$str=base64_encode('test');
$url_to_be_send=urlencode($str);
//send it via url
//now on reciveing side
//assuming value passed via get is stored in $encoded_str
$decoded_str=base64_decode(urldecode($encoded_str));

Categories