XSS Protection on Yii - php

I need to protect my web application against xss attacks via URL.
what is the best way to do this?
the application is huge, so I can not edit each of the actions, need something general.
Examples:
http://example.com/[anyproductpage.html]?source=alert('Xss')
http://example.com/catalog/?baseUrl=alert('Xss')&q=1
http://example.com/catalog/productimagezoom?index=alert('Xss')

If you aim to manipulate your actions before handle them you can use beforeAction in your controller/component, with something like this:
protected function beforeAction($action) {
#check a preg_match on a url sanitization pattern, like "[^-A-Za-z0-9+&##/%?=~_|!:,.;\(\)]", for instance
return parent::beforeAction($action);
}

This articles shows how you can make your application secure with SQL Injections, XSS Attacks and CSRF.
Hope it helps you.

Firstly, you can use regular expressions to validate your inputs, you can generalize your inputs in some regular expresions, something like this:
$num = $_GET["index"];
if (preg_match("^\d{2}$", $num)) {
//allowed
} else {
//not allowed
}
Also you can create a white list or black list, if your inputs can be grouped into what is allowed in your application, use a white list, otherwise use a black list. This lists can be sotored in your database or files, something you can easily upgrade without affecting your application. You just have to compare your inputs with that list before proccesing your inputs.
My last recommendation is encoding, you should encode your inputs and outputs, because your data from database can contain malicious code, maybe someone put it by mistake or mischief, always think in all possibilities. For this case, I remember the functions htmlspecialchars and utf8_encode, I think you should the first function, also you can analyze your inputs and build your own encoding function.
I share the following links:
http://php.net/manual/es/function.preg-match.php
http://php.net/manual/es/function.utf8-encode.php
http://php.net/manual/es/function.htmlspecialchars.php
https://www.owasp.org/index.php/XSS_%28Cross_Site_Scripting%29_Prevention_Cheat_Sheet
I hope this information helps you.
Good Luck.

for all actions in same just add a event handle to onBeginRequest:
$this->attachEventHandler('onBeginRequest', [$this, 'purifyParams']);
public function purifyParams($event)
{
$userAgent = $this->getRequest()->getUserAgent();
$isIE = preg_match('/(msie)[ \/]([\w.]+)/i', $userAgent, $version);
if (!empty($isIE) && (int) $version[2] < 11) {
$purifier = new CHtmlPurifier();
$_GET = array_map(function ($param) use ($purifier) {
return $purifier->purify($param);
}, $_GET);
}
}

Related

How to design the navigation in a php tool/website?

I'm designing a semi-basic tool in PHP, I have more experience server side, and not in PHP.
My tool contains 10-15 pages, and I am doing the navigation between them with the $_GET parameter.
In my code I have many if statements that look like:
if(isset[param1] && !isset[param2] && .....&& !isset[paramN]){
// code
}
You will agree with me, it's ugly, right?
Is it "how we do it" in PHP? or is there some kind of design pattern / functions for navigation in a PHP website?
Edit: To be clearer, what I want to know is: Is the proper way to design the navigation is with plenty of $_GET variables?
To avoid a huge if else statement try a switch statement:
$param1 = 'something';
switch (true){
case isset($param1):
echo "PARAM 1 is set";
break;
case isset($param2):
echo "PARAM 2 is set";
break;
default:
echo "None set";
}
And to answer your edit - Yes, you can use _GET variables for navigation and it is normal.
Actually the solution to this problem is a little bit complicated, than it might seem at first glance. And you need to implement a handler for that, since you're looking a cleanest way of handling GET parameters and invoking a code fragment.
In your case, your final API, should look like this (since you were asking for the design, not the for implementation):
$nav = new Nav($_GET);
$nav->whenSet('param1', 'param2')->andNotSet('param3')->then(function(){
});
$nav->whenSet('param3')->andNotSet('param1', 'param2')->then(function(){
});
// Or a simpler and shorter way
$nav->register($existingKeys, $nonExistingKeys, function(){
});
Another option you have is to use a routing mechanism. Most PHP frameworks provide this functionality. They all support optional route fragments, so you can handle parameters only defining one route path, like this /page/? (? - means optional).
This is my suggestion add conditions in an array and than use in_array()
echo in_array($yourVar, array('abc', 'def', 'hij', 'klm', 'nop'))
? True
: false;
UPDATE:
$get = "abc";
$navigation = array(
"abc"=>"yourneed",
"def"=>"yourneed2",
"ghi"=>"yourneed3",
);
foreach($navigation as $key => $value){
if($key == $get){
echo $value;
}
}
One more solution you can define routes also.
Same as CI and YII.
(I'm not using switch but you should definitely try that, and try using break between cases)
I'm using this at the moment, it seems to avoid mass-IFfing:
if (!$_GET) {
homePageFunction();
}elseif($_GET) {
contentPagesFunction($_GET['p']);
}
I have a menuer() function that outputs rel paths to content 'things' in links like:
<a href='?p=$relPath'>$name</a>
Although I could probably use different notation to tidy it further... Untested but like this:
if (!$_GET) homePageFunction();
elseif ($_GET) contentPagesFunction($_GET['p']);

How to protect $_POST and params from hackers [duplicate]

This question already has answers here:
What are the best PHP input sanitizing functions? [duplicate]
(14 answers)
Closed 7 years ago.
I'm using this with html2canvas.js to generate and save images from HTML.
I use url params to make this work - eg: website.com/?price=10&name=xxx
All ok untill here - the script works fine - images are saved in /cart/ dir
<?php
$image = $_POST['image'];
$username = $_POST['username'];
$front_class = $_POST['front_plass'];
$decoded = base64_decode(str_replace('data:image/png;base64,', '', $image));
$date = date('d-M-Y-h-i-a', time());
$curdir = getcwd();
$cartDir = $curdir ."/cart";
$userDir = $cartDir.'/'.$username;
if (!file_exists($userDir)) {
mkdir($cartDir.'/'.$username, 0777);
}
$name = $front_class."-front-".$date.".png";
$full_path = $userDir.'/'.$name;
$name1 = 'cart/'.$username.'/'.$name;
function ImageFillAlpha($image, $color) {
imagefilledrectangle($image, 0, 0, imagesx($image), imagesy($image), $color);
}
function imageCreateCorners($sourceImageFile, $name, $radius) {
...
}
file_put_contents($full_path, $decoded);
imageCreateCorners($full_path, $name, 25);
echo '<img src="'.$name1.'" alt="front" id="front_img" />';
?>
And the js
html2canvas($('#front'), {
"logging": true,
//"proxy":"html2canvasproxy.php",
"onrendered": function(canvas){
var dataURL = canvas.toDataURL("image/png");
$.post('image_front.php',{
image: dataURL,
username: username,
front_class: frontClass
},function(data){
$('.imageHolder_front').html(data);
});
}
});
The problem is that someone hacked me twice yesterday thought this and I need to protect the $_POST or the params can be the problem?
Any help here please? I'm not really good with backend development - more with frontend.
Thanks.
You made a couple of big mistakes.
First, validate your POST data as #JohnConde said, don't use them directly in your code, ever.
Second, don't create directory with 777 permission on your server, since everybody will be able to write into it and hack you that way.
You cannot "protect" parameters. Your server is a box which receives arbitrary HTTP requests and returns HTTP response. Realise this: anybody can send any arbitrary HTTP request to your server at any time containing any data they wish. You do not control what somebody sends you. The only thing you control is what you do with this data. Expect this data to not conform to your expectations. In fact, expect it to be malicious. Validate it instead of assuming it conforms to any particular format. Never blindly use user provided data in something like SQL queries or in constructing file paths without escaping/binding/validating/confirming the data, or you might be building strings you didn't expect to.
This is the one fundamental truth of all programming. You need to write your applications from the ground up with this in mind. There is no easy fix, there's only diligence.
Sanitize your user input. In general: Don't ever ever ever trust user input!
I would recommend the very good writeup from #Charles in the first answer of this question: What are the best PHP input sanitizing functions?
Hackers can hack even if you are not using url parameters.
It has to be done in the backend. Before interacting with database you have check whether the parameters are what you are expecting.
For example you should not allow single quotes in your params, this will actually allow hackers to add some more queries to your query.
Use mysqli prepared statements

How to avoid xss atack in php codeigniter

I am relatively new to web development. And just today my teacher told me to implement a method to avoid cross server scripting in my project. I have searched a lot and found about xss_clean but i am not sure how to use and implement it. Any guide or article related to that would be welcome. Or if you want to explain here that would save me a lot of extra hard work i will be very thankful to you. I am using CodeIgniter framework so please any article related to that would be good.
The problem with XSS vulnerabilities is that you can't just apply one fix. These vulnerabilities can occur in every little thing you write.
XSS happens when an attacker is able to inject HTML into the page of a visitor of your website. Depending on what that code is he could send the visitor to his phishing website or steal his session.
It's not hard to imagine how you can prevent HTML injection: you just HTML-escape all user input. But in practice there can be quite a bit of this and your system is only as secure as the weakest link.
From my experience, CI's XSS is pretty good -- I have run into situations where it does remove something which I have wanted which can be a pain to debug if you're not expecting it. I've never been able to "easily" circumvent it nor have I read about any exploits (and the CI community is fairly large).
For details take a look below link which may help you
http://blog.astrumfutura.com/2011/05/codeigniter-2-0-2-cross-site-scripting-xss-fixes-and-recommendations/
Read this also https://www.owasp.org/index.php/XSS_%28Cross_Site_Scripting%29_Prevention_Cheat_Sheet
http://htmlpurifier.org/
for removing xss attack you can do following things:
you need to remove unwanted tag like "script" from post and get value.
remove meta-characters from post and get value.
a very short and simple answer use following line of code where you are submitting your details that mince in your controller file.
$data = $this->security->xss_clean($data);
here data may your single value or array in case you have multiple records.
one more addon to your query.use following to protect from sql injection
$username = $this->input->post('username');
$query = 'SELECT * FROM subscribers_tbl WHERE user_name = '.
$this->db->escape($email);
$this->db->query($query);
I have implemented this functionality for protection against XSS attacks:
public static function protectArrayAgainstXSS(&$arr) {
$changed = false;
foreach ($arr as $index => $a) {
if (is_array($a)) {
$changed = $changed || Common::protectArrayAgainstXSS($arr[$index]);
} else if ($a !== null) {
$changed = $changed || ($arr[$index] === strip_tags($a));
$arr[$index] = strip_tags($a);
}
}
return !$changed;
}

Update database using JQuery ajax.Post()

Help! I'm writing some code to update a mySQL database using similar to the code below:-
$.post('http://myURL.com/vote.php?personID=' + personID + '&eventID=123');
The vote.php code takes the querystring values and inserts a record into a database with those values in it.
This kind of code is working fine, but I've realised the problem is that people could just type something like:
http://myURL.com/vote.php?personID=5&eventID=123
into their address bar and essentially spam the app...
Is there a straightforward way I can ensure this doesn't happen? I'm reasonably new to these technologies so not aware of how everything works or fits together, but I'm learning fast so any pointers would be super useful.
It is not a good idea to use GET parameters for data that goes to a database. Generally, you want to use POST parameters which are not visible in the URL. So instead of :
$.post('http://myURL.com/vote.php?personID=' + personID + '&eventID=123');
You would do it like this :
$.post('http://myURL.com/vote.php', { "personID" : personID, "eventID" : 123 });
And in your PHP script, you would access your data with the $_POST array like this :
$personID = $_POST['personID'];
$eventID = $_POST['eventID'];
However, don't forget to properly filter input before saving to the database to prevent bad things like SQL Injection.
This is not a silver bullet : spam will still be possible because any HTTP client will be able to send a post request to your site. Another thing you can look at is Security Tokens to make it even less vulnerable to spam. Or implement a system that limits the number of request/minute/user... but I'm getting too far from the original question.
Correct syntax of $.post is
$.post(url,data_to_send,callback_function)
By using this method your user will never be able to damage your site.Use like
$.post('http://myURL.com/vote.php',{"personID":personID,"eventID":123);
Whether you're using POST or GET, you could always consider signing important fields in your page by using hash_hmac. This prevents people from changing its value undetected by adding a signature that no one else can guess.
This also makes CSRF more difficult, though not impossible due to fixation techniques. It's just yet another technique that can be put in place to make it more difficult for "fiddlers".
The following function adds a salt and signature to a given person id to form a secured string.
define('MY_SECRET', 'an unguessable piece of random text');
function getSecurePersonId($personId)
{
$rnd = uniqid("$personId-", true);
$sig = hash_hmac('sha1', $rnd, MY_SECRET);
return "$rnd-$sig";
}
You would pass the output of getSecuredPersonId() to JavaScript to pass as data in the $.post() or $.get(); posting would be recommended btw.
When the form is submitted your person id would end up in either $_GET['personID'] or $_POST['personID'] depending on the request method. To validate the given value, you run it through this function:
function validateSecurePersonId($securePersonId)
{
if (3 != count($parts = explode('-', $securePersonId))) {
return false;
}
// reconstruct the signed part
$rnd = "{$parts[0]}-{$parts[1]}";
// calculate signature
$sig = hash_hmac('sha1', $rnd, MY_SECRET);
// and verify against given signature
return $sig === $parts[2] ? $parts[0] : false;
}
If the value is properly signed, it will return the original person id that you started out with. In case of failure it would return false.
Small test:
$securePersonId = getSecurePersonId(123);
var_dump($securePersonId);
if (false === validateSecurePersonId($securePersonId)) {
// someone messed with the data
} else {
// all okay
}

Best way to prevent SQL Injection when preparing statement is impossible

I have to work on an old site with major security issues : SQL Injections are really easy to perform.
Obviously, the best way to prevent this kind of attacks is to escape what is used in query (prepare statements with PDO, mysql_real_escape_string with MySql, etc.) but we can't do that quickly : the whole site is procedural PHP (no class), the queries are "prepared" everywhere, there are hundreds of pages and thousands of users everyday, and a new version wil come as soon as possible.
So since this morning the following function is called on each request to detect suspicious POST or GET parameters based on keywords.
const SQLI_UNSAFE = 3;
const SQLI_WARNING = 2;
const SQLI_SAFE = 1;
const SQLI_MAIL_DEST = 'monmail#mondest.com';
function sqlicheck() {
$params = array_merge($_GET, $_POST);
$is_warning = false;
foreach($params as $key=>$param) {
switch(getSafeLevel($param)) {
case SQLI_SAFE:
break;
case SQLI_WARNING:
$is_warning = true;
break;
case SQLI_UNSAFE:
mail(SQLI_MAIL_DEST, 'SQL INJECTION ATTACK', print_r($_REQUEST, true).' '.print_r($_SERVER, true));
header('Location: http://monsite/404.php');
exit();
}
}
if($is_warning === true) {
mail(SQLI_MAIL_DEST, 'SQL INJECTION WARNING', print_r($_REQUEST, true).print_r($_SERVER, true));
}
}
function getSafeLevel($param) {
$error_words = array('select%20','drop%20','delete%20','truncate%20','insert%20','%20tbclient','select ','drop ','delete ','truncate ','insert ',);
$warning_words = array('%20','select','drop','delete','truncate', ';','union');
foreach($error_words as $error_word) {
if(stripos($param, $error_word) !== false) return SQLI_UNSAFE;
}
foreach($warning_words as $warning_word) {
if(stripos($param, $warning_word) !== false) return SQLI_WARNING;
}
return SQLI_SAFE;
}
This seems to detect some kinds of attacks but it's clearly very basic. Any ideas to improve it? Any major issue ?
First, make sure that the database user executing the queries only has select, update, delete permissions. If the user can't execute drop, there's no way it'll happen (this assumes that your users will never need to create or drop tables, but if they do, you can create table level permissions to protect the big tables).
Second, your script will only tell you what people are using; it won't do a site wide check of what queries are possible; if there's a section of your site that isn't used much, you won't get any mail telling you. Better to just comb through the code with a search tool.
After that, you have to start modifying the code and doing escaping and validation, and that's just going to take a while.
Why not just use real_escape_string() htmlentities() stripslashes and filter classes of php and log the SQL queries so that you can see what people are sending you, use sha256 with some md5 you will be ok other thing is for quick action just send login data in binary format

Categories