Given the following simple code:
function loadthis ($var)
{
$id = $this->model->get_id($var);
}
Question: can any malicious code ever be passed via a URI variable?
Scenario: www.mydomain.com/mycontroller/loadthis/dosomethingreallybadhere
Extra info:
I use active record on the model, so I know they cant do SQL injection
In this example I am NOT using the form_validation class (but I use it in other places for my forms)
I limit my URI characters to the default ones provided by Codeigniter
$config['permitted_uri_chars'] = 'a-z 0-9~%.:_\-';
There isn't too much you can do with the characters allowed ... mainly what you are attempting to prevent is anyone injecting MySQL or possibly malicious scripts into your site. There is always a possibility but I think you are fairly safe with what you have. The main things you want to filter are:
Quotes, Single Quotes, and Semi colons since these can be used for a MySQL injection attack.
HTML markup characters such as < or > since these can be used to inject malicious scripts.
This is by no means a end all list. These are the primary things you should be on the lookout for. I would highly recommend you read up on security best practices at https://www.owasp.org/index.php/Main_Page
Yes and no.
"Data" by itself is never dangerous, it's just data. It depends on what you do with it that may have unwanted consequences if the data contains something you did not expect. So, for data received via the URL, or really any data received from somewhere the user has control over, you cannot know or guarantee what that data contains. Hence, do not write code that uses this data and will either break or open security vulnerabilities should that data contain something you did not anticipate.
Data with unknown content is not dangerous if you treat it as an alien object and handle it accordingly. It is dangerous if you treat it as if you know what's in it, even though you don't. Yes, that's a convoluted answer. ;)
It depends on the code, of course. You can't never say "it's perfectly safe" without analysis all the code base. Your restricted URL charset seems reasonable (if it's sufficient for your application). However I can imagine at least one example where the input could be malicious, if the user puts \..\..\ in the URL, which could in some case open a custom file (on Windows).
If you are only concerned about SQL injection, if you have a code like this:
SELECT * FROM articles WHERE article_id = $id
Malicious user can set $id to 0 or 1 like 1 which passes your restricted charset.
The same can be done for XSS, if you somewhere forget to escape properly (happens often in generated JavaScript code), but the example is harder to think of.
Anyway, there is no true/perfect/safe way to restrict user input to get security. The only way to avoid XSS/SQL/whatever injection, is to go through all your code and make sure that wherever you either use for input or output some variable, it is properly escaped according to the used context. The rule is don't restrict input, but be prepared that is can contain anything.
If the input is a string, be prepared is can contain any characters and deal with it. Save it into the database as it is, and make sure that during the saving it can't do any harm. If you need to escape it when building the SQL query, escape it in there. If you need to put the string (or part of it) into a HTML output, escape it properly. Of course you need to be very careful to make sure you do proper escaping at all places.
Related
Hey guys so Ive got a question, is there a something I could use when inserting data into the SQL to prevent XSS? Instead of when reading it.
For example I have quite bit of outputs from my sql that are user generated, is it possible to just make that safe on Entering SQL or do I have to make it safe when it leaves SQL?
TL:DR can I use something like htmlspecialchars when inserting data into SQL to prevent XSS, will that be any sort of good protection?
I think several things are mixed up in the question.
Preventing XSS with input validation
In general you can't prevent XSS with input validation, except very special cases when you can validate input for something verz strict like numbers only.
Consider this html page (let's imagine <?= is used to insert data into your html in your server-side language because you hinted at PHP, could of course differ by language used):
<script>
var myVar = <?= var1 ?>;
</script>
In this case, var1 on the server doesn't need to have any special character, only letters are enough to inject javascript. Whether that can be useful for an attacker depends on several things, but technically, this would be vulnerable to XSS with almost any input validation. Of course such assignment may not currently be in your Javascript, but how will you ensure that there never will be?
Another example is obviously DOM XSS, where input does not ever get to the server, but that's a different story.
Preventing XSS is an output encoding thing. Input validation may help in some cases, but will not provide sufficient protection in most cases.
Storing encoded values
It is generally not a good idea to store values html-encoded in your database. On the one hand, it makes searching, ordering, any kind of processing much more cumbersome. On the other hand, it violates single responsibility and separation of concerns. Encoding is a view-level thing, your backend database has nothing to do with how you will want to present that data. It's even more emphasized when you consider different encodings. HTML encoding is only ok if you want to write the data into an HTML context. If it's javascript (in a script tag, or in an on* attribute like onclick, or several other places), html encoding is not sufficient, let alone where you have more special outputs. Your database doesn't need to know, where the data will be used, it's an output thing, and as such, it should be handled by views.
You should test the input for whitelist characters using a regex to only accept like [a-Z][0-9] for example. You'll have a big headache if you try the other way around, using a blacklist, because there are gigantic ways of exploiting input and catching them all is a big problem
Also, be aware of SqlInjections. You should use SqlMap on linux to test if your website is vulnerable
I need to prevent XSS attacks as much as possible and in a centralized way so that I don't have to explicitly sanitize each input.
My question is it better to sanitize all inputs at URL/Request processing level, encode/sanitize inputs before serving, or at the presentation level (output sanitization)?
Which one is better and why?
There are two areas where you need to be aware:
Anywhere where you use input as part of a script in any language, most notably including SQL. In the particular case of SQL, the only recommended way of dealing with things is the use of parameterized queries (which will result in unescaped content being in the database, but just as strings: that's ideal). Anything involving the magic quoting of characters before substituting them directly into the SQL string is inferior (because it's so easy to get wrong). Anything that can't be done with a parameterized query is something that a service secured against SQL-injection should never allow a user to specify.
Anywhere where you present something that was input as output. The source of the input could be direct (including via a cookie) or indirect (via the database or a file). In this case, your default approach should be to make the text that the user sees be the text that was input. That's very easy to implement correctly since the only characters you actually have to quote are < and &, and you can wrap it all in <pre> for display.
But that's often not enough. For example, you might want to allow users to do some sort of formatting. This is where it is ever so easy to go wrong. The simplest approach in this case is to parse the input and detect all the formatting instructions; everything else needs to be quoted properly. You should store the formatted version additionally in the database as an extra column so that you don't need to do much work when returning it to the user, but you should also store the original version that the user input so you can search over it. Do not mix them up! Really! Audit your application to make totally sure that you get this right (or, better yet, get someone else to do the audit).
But everything about being careful with SQL still applies, and there are many HTML tags (e.g., <script>, <object>) and attributes (e.g., onclick) that are never ever safe.
You were looking for advice about specific packages to do the work? You really need to pick a language then. The above advice is all totally language-independent. Add-on packages/libraries can make many of the steps above really easy in practice, but you still absolutely need to be careful.
I have a page where I want to accept an email address in the GET parameters. If I use FILTER_VALIDATE_EMAIL, am I still vulnerable to xss and javascript injection attacks, and the like?
I'm not asking if it's a good, or good enough, validator of email addresses. I want to know if one can still inject bad web code through arbitrary strings passed through it -- do I need to do additional filtering to prevent that?
Yes, a valid email address can easily be used as the container for some carefully crafted strings that can be used to attack you.
Get out of the "filtering" mindset and get into the "escaping" mindset. A universal "make it safe" filter simply doesn't exist. It cannot exist, because all escaping must be done in a context-specific manner.
For example, if the email address will be output to a plain text document, then nothing is needed to be done. If it's being output into an html document, as a text node, then it needs to be escaped for an html context, so escape html special characters and entities. If it's being put into an html document, and it's value will be inside of an html attribute, then very very careful escaping would need to be performed, and it would depend on which html attribute. If it's being used in an sql query, then it needs to be escaped via a database specific escaping function, and even then you must escape differently if you're using it as a parameter value (i.e., where someColumn = '$paramVal'), vs a symbol name like a table name, a column name (i.e., order by $myEscapedColumnName DESC). and so on.
It's all about context of use, not content of the string. This goes for everything (not just emails or other user input), and it's not just a matter of security, but it's a matter of programming and syntax correctness. Proper escaping is complicated, and takes a lot of time to learn, and careful thought and consideration when you code. Many coders don't bother doing it due to the effort, and they are the ones who cause the company to get hacked.
fyi, the email address spec allows quoted strings, so something you could inject strings like "<script>alert('xss')</script>"#example.com. The possibilities are obvious.
That should be good enough, but naturally you should still escape it when entering it into a database, etc. You never know what kind of bug may exist in PHP or Apache, etc, that may allow an attack to happen anyway.
I'm trying to secure my script a bit after some suggestions in the last question I asked.
Do I need to secure things like $row['page_name'] with the mysql_real_escape_string function? example:
$pagename = mysql_real_escape_string($row['page_name']);
I'm asking mainly because when I do secure every row I get some errors like when trying number_format() it throws number_format() expects parameter 1 to be double, string given while when it is not secured with mysql_real_escape_string it works.
Can someone clear this for me? Do I only need to secure COOKIE's or the row fetches too?
I got the suggestion in this post: HERE (look at the selected answer)
You're doing it backwards. Presumably $row is a row coming out of the database. You don't mysql_real_escape_string on the way out of the database, you use it on data going into the database to prevent SQL injection. It prevents people from submitting data that contains executable SQL code.
Once the data is safely in the database, you're done with mysql_real_escape_string (until you attempt to update that data). User data coming out of the database needs to be run through htmlspecialchars before it hits the page to prevent script injection.
Basically, on the way to the database, just before your insert/update runs, you need to escape potentially executable SQL. On the way to the browser, just before strings leave your app for the browser, you need to escape potentially executable JavaScript and/or interpretable HTML. Escaping should be the last thing you do with a piece of data before it leaves your app for either the browser or database.
This is by no means a complete answer.
Before writing any more code you need to stop and consider exactly what it is you are trying to accomplish.
In other words, what are you gaining by running the mysql_real_escape_string function?
Generally speaking, you escape data submitted by the client. This is to help prevent sql injection. Also, you should go further to actually validate that what the client sent in is acceptable (ie. "Sanity Check"). For example, if you are expecting a numeric entry, don't accept strings and range check the values. If you are expecting string data like a name, don't accept HTML, but again range check to verify length is acceptable. Both of these situations occur when the client submits data, not when you are writing it back out.
Going a little further, your cookies should be encrypted and marked with the httponly flag to tell the browser that it is not for use in client side script. Even with that, you shouldn't trust the data in the cookie at all; so go ahead and run your sanity checks and still escape those values in queries.
I highly recommend that you go to the OWASP website and read through all of the issues to get a better understanding of how attacks work and how to defend against them. Web App security is too important to just start coding without really knowing what's going on.
BTW, kudos to you for learning about this and trying to defend your site. Too many devs don't even think about security at all.
If you use the PDO extension to build clean requests, you can create functions that will do this (secure strings and define their type) :
An exemple where $text is a string of text and $number is an integer :
public function InsertThis($number, $text) {
$pdo = $this->getPdo();
$sth = $pdo->prepare("INSERT INTO my_table (number, text) VALUES (:number, :text");
$sth->bindParam('number',$number,PDO::PARAM_INT);
$sth->bindParam('text',$text);
$sth->execute();
}
http://php.net/manual/en/book.pdo.php
You only need to use mysql_real_escape_string() when inserting/updating a row where the values have come from untrusted sources.
This includes things like:
$_GET
$_POST
$_COOKIE
Anything that comes from the browser
Etc..
You should only use it when putting things into the database, not when you are taking things out, as they should already be safe.
A safer way altogether is to use the PDO class
mysql_real_escape_string does not "secure" anything. It escapes characters that can be used in sql injection attacks. Therefore the only values that you should escape are the ones supplied by your users. There should be no need to escape things that come out of your own database.
On my website I have a variable called $user_data that contains input from a form. I then show this variable on the user page (via echo).
What is the best method to avoid any security risks with this variable? I use strip_tags(), but it is not enough.
This variable also gets saved to a MySQL database.
There are two very important things you must do to avoid serious security problems.
You need to escape the user input before putting it in your SQL query. Escaping means escape all the special characters such as '; luckily, there is a function that already does it automatically: mysql_real_escape_string.
If you don't escape user input nasty things could happen. Imagine that your query is INSERT INTO userdata VALUES ('$user_data'). Now imagine that the user wrote '; DROP DATABASE userdata;.
If you don't escape it, your query will become: INSERT INTO userdata VALUES (''; DROP DATABASE userdata;'). As you can imagine this is not good: if you have multi statements enabled you can kiss goodbye to your database. This is called an SQL Injection attack.
When you are outputting your variable to the user you also need to properly replace HTML special characters with HTML entities. Luckily, there is a function to do that too: htmlspecialchars(). It will transform the special HTML characters such as < to <.
This seems to be a problem that is often underestimated, but in reality it's very serious. Imagine if $user_data contains <script>SomeNastyScript()</script>. It could exploit existing vulnerabilities in the browser of your users, or it could send a non-HTTPOnly cookie (that may contain saved passwords) to the attacker, or it could trick the user into writing their password on a form generated through the manipulation of the DOM (possible in javascript), or a lot of other bad things.
This is called XSS (Cross-site scripting).
Short version
Call mysql_real_escape_string on the string before inserting it into your SQL query (but not when you echo it).
Call htmlspecialchars on the string before displaying it to the user (but not when you put it in the database).
When you're going to output something, strip_tags or htmlspecialchars is fine. I prefer the latter, since you then don't totally destroy <3 and the like that were never meant as HTML tags anyway.
When putting a value directly into a query, mysql_real_escape_string is the appropriate way to escape, or just using PDO and prepared statements.
Of course, it's best to do these escape methods only when you're about to need them, rather than applying both to all variables ever. It's always a pain to have to strip the slashes back out of a MySQL-escaped variable if you want to actually work with it before putting it into the database, and that's no better than PHP4's magic quotes. Similarly, you don't want to turn someone's password of "one<two" into "one<two" before inserting it into the database. (Obviously, you shouldn't be storing plaintext passwords, but the generic example stands.)
There is not a thing called "secureness".
No way to just secure an abstract variable. Everything depends on the scenario.
A condoms commonly used for safety. Would you secure your money with a condom? I suppose - no.
Same here.
You'd better distinguish these 2 matters - a database security and displaying security.
Database one is little more complicated than just "Call mysql_real_escape_string". I've described all the rules comprehensively in this answer
You can also do this:
$way = preg_replace('#[^a-z0-9]#i', '',
strip_tags(htmlentities(htmlspecialchars(mysqli_escape_string($db_conx, $_GET['way'])))));