Ask Slashdot: Verifying Security of a Hosted Site?
edi_guy writes "I'm getting ready to launch a small commercial website that will contain customer information in a MySQL database that will be run by a web-hosting service. While I have good experience with SQL databases from a programming point of view, I'm not an expert on securing them. Given all of the publicity around break-ins and data theft on a seemingly daily basis, it seems prudent to review this now rather than later. What are suggestions on resources that would help verify that both myself and my hosting service are following best practices on securing a database backed website?"
contract some penetration tester like the one from offensivesecurity
Jehovah be praised, Oracle was not selected
This is a good starting point:
http://code.google.com/p/owasp-development-guide/
Make sure that you setup your mysql server to only accept connections from your server(s).
And get something like Fail2ban if you are using linux to stop brute-forcing.
Store salted hashes of passwords.
Don't have the SQL server exposed to the internet. Firewall it so only the Web server(s) can access it.
Only expose the web servers HTTP port(s) to the internet and keep them up to date.
Use parameters (and stored procedures) exclusively if at all possible
Normal people worry me!
Ask them what their security plan is? How often do they conduct internal and external security scans? Do they conform to any security standards, like NIST, SANS, or even PCI? Also, ensure you have permission to conduct your own security scans, and ask them if you get results where there is a CVSS score of 4.0 or greater.
But this is slashdot. A slashdoter who didn't build his own computer is like a Jedi who didn't build his own lightsaber!
From what I know, I would say that having a good password policy is first and foremost. Secondly, ensure that your MySQL server is only accessible from IP Addresses on the whitelist. Hash your passwords and make sure you salt them. No one likes a good hash without some salt. The biggest threat is an injection. Make sure you sanitize every single input on your site, don't trust cookies for security, and make sure you're regularly validating your security tokens. Oh, and don't be an idiot. There is no reason for you to store anything more than the last four digits of a customers credit card number anywhere on your server.
...then you have to go back to basic principles, which isn't compatible with a hosted site.
In an ideal world, you'd have a public network (the Internet connection) and a DMZ/semi-private network, with the DB server. The web daemon wouldn't run on the DMZ side, and would have to forward requests through to the other server.
It's been a really long time since I dealt with this stuff firsthand, but I suppose that on a single box one could create a virtual network or use loopback to connect the web daemon to the DB daemon, and then restrict the DB daemon to only communicate on the virtual side, but you'd probably still need local root access to set everything up.
From what I gather, many hosting companies that offer space on a box with multiple other customers typically have a DB guy on staff to work with this kind of thing, and they typically charge for the both the cgi bin and for the DB component. As I said though, it's been a LONG time since I've dealt with this stuff personally (like, people were still using compiled-C for server-side coding), so things might have evolved from my mindset.
Do not look into laser with remaining eye.
Follow these: https://www.pcisecuritystandards.org/ and profit.
Second step, don't use a hosted site
Make sure not to use a server application or OS someone else wrote or maintains either. Definitely don't use anything that requires a third party to provide the updates or patches.
On second thought: "Third step, don't connect the web site to the internet."
Seriously... you have to host things, or it will be very expensive to put your site up by building all the infrastructure yourself, or you cut corners and not have the protections (like design, cooling redundancy, power redundancy), a real datacenter operation provided by a hosting provider would.
Trying to host a web site on home/business DSL is bound to be a failure. Good luck dealing with unexpected load spikes, also.
"Not hosting the site" is not a realistic solution for most people.
You need to pick a hosting provider that will work with you to ensure security, and who had third party validations to show you, is willing to cooperate with third parties to validate security, and will attest to / provide you some documentation of their own security practices (esp. physical security with regards to servers you colocate), OR their practices for dedicated servers (second best security option) -- e.g. who has access, what controls exist, etc; shared servers (where multiple customers have sites on the same OS install) are potentially dangerous in some regards.
Get your site penetration tested. Ask you host if they have had thier server's standard build (or SOE) reviewed by security experts also. I can help with these if you need, drop me a line!
No, there's a little thing called a dedicated (or colocated) server. If you are sharing a server, which most people would call "hosted," then you are vulnerable to whatever problems they introduce.
Ask them what their processes and policies are in regards to this. They're your supplier, make them tell you why you should trust them with your DB.
That said....firstly understand that securing the database is a small piece of a very big complicated jigsaw made up of randomly cut pieces with an abstract painting on them. Security is hard.
My first step is always to get the infrastructure up to something I'm happy with.
* Set your firewall to block all incoming connections by default, only ever allow connections to port 80 (and 443 if necessary) on your web server/load balancer.
* Designate a couple of 'management IP addresses'. IE your home, or another location. Open up SSH to these addresses only.
* Configure SSH so the only way to access it is via certificates. Do not allow tunnelled plaintext passwords, ever.
* Try to ensure all your secret SSH keys are password protected
* For all server management issues use SSH. Use it for uploading, direct DB access, deploying etc. The only external connections to any of your servers happen on port 443/80/22.
* If you are using SSL use a secure cipher suite (running SSL Digger) will tell you if you are using any weak ciphers
* Decide on an update policy (ours is to have a human monitor all package updates daily, decide when an important one comes out, test it on stage, then update production) that ensures critical security fixes are applied quickly
* Google "security guide app" and review what the Internet says about securing Apache/Lighttpd/Squid/MySQL/RabbitMQ/Whatever. Understand it! Pay particular attention to anything the user interacts with (ie Joomla/Drupal/Wordpress)
Hmm, that's a pretty big list, mostly incomplete, and isn't even where your big security problems lie - most attack vectors are likely to come through flaws in your application. SQL Injection (shockingly!) is still happening, and if you give users the opportunity, someone WILL shoot themselves in the foot.
Man, security is hard! You can hire an agency to test things for yuo and give you a report. These tend go from quite cheap (ie the firm just ran Nessus and sent you the output) to extremely ellaborate white-box penetration testing that usually comes back with practical real world advice.
Great that you are concerned enough about this to ask Slashdot, don't work for Sony do you ;)
MySQL is not uniquely prone to injection attacks. All that requires is unescaped user input.
FanFictionRecs.net
1. Read up on SQL injection attacks. Escape all parameters coming in on the pipes.
2. Put the db on a different server and firewall it so it cannot be accessed from the internet. Ideally you would have a 3 layer design with the web host passing requests to an application running on a firewalled server not accessible to the internet, and the application would pass requests through another firewall to the db server running on a machine not accessible to the web host.
3. Don't store anything you don't have to.
4. If you have to store it, encrypt it.
5. Use SSL whenever receiving or transmitting private information.
6. Teach you end users about password security.
7. Under no circumstances store unhashed passwords or send passwords out via email.
Uhh, right, because a poorly written web application won't be able to execute SQL if another DBMS is used.
1. Do not use the MySQL root pass as the application password. Do not use the root user as your application user.
2. Setup an application specific id and only give it SELECT, UPDATE, DELETE for the specific tables of the application or to the application schema only.
3. Passwords for these ids must be 15 chars long
4. DB Passwords stored in application files must have the correct ACLs.
5. Learn how to use the creation of the user id to lock the db for access only from the application server. For example if your app server is at 192.168.0.4 then the application user would be applicationuser@192.168.0.4. This 'locks' the db from only accepting traffic from the server listed. If the db is colocated with the app server, then specify the user like this - applicationuser@localhost. Also assuming you need to login to the DB server to do maint then your root user would be root@localhost. This would force you to have localhost access before you could login as root.
6. Use a Object Relational Mapping technology to front the DB, thus preventing SQL injection attacks. If you must script, NEVER EVER concatenate SQL. If no ORM is availble, use whatever languages parameterized SQL scheme.
There is probably more here, but this should give you a fairly good start.
Good luck
MySQL doesn't inherently open you up to SQL injection... Poor programming practices opens you up to SQL injection. Any SQL based database is vulnerable if someone stupid writes the program.
The standard lines about SQL injection:
DO use prepared statements with place holders e.g. "SELECT * FROM table WHERE id = ?"
DO NOT use string concatonation "SELECT * FROM table WHERE id = '" + some_string + "'";
DO sanity check anything passed into your database
DO NOT use user input as an identifier (column, table, or view name) E.G. "SELECT * FROM "+user_input+" WHERE 1=1";
DO make users for your database that have the least amount of permissions required to run your app (Only UPDATE, INSERT, DELETE, SELECT)
If you want I can offer you a web site security audit (specialized company), for free.
Get the documents. Have you and your host assess your setup.
https://www.pcisecuritystandards.org/security_standards/index.php
Also have security scan firms run scans of your site.
As mentioned earlier, hire someone to check out your security measures. Many companies do this. Sadly i can't remember any names off the top of my head, but google is probably not completely clueless.
And obviously: Make sure that the contractors are legit and not just in it to rig the system with backdoors
this is probably the most boring sig in the world
Hosting secure, high-reliability, high-availabity web sites isn't a do-it-yourself proposition. Perhaps you should have your site hosted by a top quality vendor who has the staff and expertise to maintain the physical and software security.
The problem is that this type of hosting isn't cheap. The bargain basement hosting firms will not provide the expertise and customer support necessary.
Unless you're really going to scale up quickly, it's unlikely that you can hire (or become) expert in all of the domains necessary to provide top tier hosting. For example, can you accurate manage the A/C needs for your site hosting? Do you have guaranteed service contracts on the A/C units an N+1 back ups? Same with power, backups, hot off-site recovery, physical security, insurance, fuel for your generators, battery contracts?
I'd go with a top-tier hosting firm, and be prepared to pay significantly more than $10/month.
Also, don't listen to clueless Anonymous Cowards on Slashdot who don't know anything but the subject at hand - but comment anyway
Just because you're paranoid doesn't mean there isn't an invisible demon about to eat your face
Not to belabour the obvious, but why not start here:
http://dev.mysql.com/doc/mysql-security-excerpt/5.5/en/security.html
That and never, ever insert user-supplied data into a query without using the vendor approved escape mechanism, even if you've done your own safety checks.
http://dev.mysql.com/doc/refman/5.5/en/string-functions.html#function_quote
"Man is nothing without the works of man" -- Helvetius
1. Start with a hosting service you can trust. Either look at the ads in a five-year-old edition of "PC Magazine" and choose one that's still in business, or find a brick-and-mortar business in your hometown. Do a background-check on the owners. Ask for references. 2. Use stable open-source software (Joomla, OScommerce, whatever) as much as possible instead of rolling your own. Watch out for security patches. If you do write your own code for the site, hire another set of eyes to look at it. 3. Develop a backup plan early on ... ideally before the site goes live.
MySQL has appalling code quality, and a critical piece of proprietary technology. Use PostgreSQL: safer, more standards-compliant, more robust, totally free, more scaleable.
Leandro Guimarães Faria Corcete DUTRA
DA, DBA, SysAdmin, Data Modeller
GNU Project, Debian GNU/Lin
Given all of the public break-ins, of huge companies, don't try.
Leasing a colocated server is a relatively inexpensive intermediate option. Most decent ISPs have the option available. Prices typically range from $50 to 200/month depending on hardware specifications/bandwidth requirements.
The next step up is to lease space in a colocation rack from the ISP. That is your hardware in a locked rack in their server room.
"You want to know how to help your kids? Leave them the fuck alone." -George Carlin
Post some inflammatory content concerning Anonymous. Include boasts about being invulnerable to retaliation.
Alternately,
DO create stored procs / functions and grant your scripts execute privs (and not much else). This can be a pain to implement, but it is the most "elegant" solution since you're forced to properly decouple DB functionality from front-end logic. Plus it makes it easier to add different front-ends later if you go multiplatform or something...
-or-
DO run all user-sourced input through "mysql_escape_string" or your DBMS' equivalent. Most DAO implementations already do this.
Prepared statements are a decent half-step, but they aren't easily applicable to variable-length queries such as "advanced search" or anything else with optional parameters. It's far too easy to hit one of these walls and fall back into sloppy coding to get around it, negating what little advantage the prepared statements offered.
-Billco, Fnarg.com
Bobby Tables: A guide to preventing SQL injection
My other car is a 1984 Nark Avenger.
If you don't control everything on the box, you can't ensure security.
Regardless of what they claim or what they do, you're essentially sharing the box with hundreds or thousands of other users who potentially have access to run whatever they feel like.
I would suggest a Virtual Private Server on Linode. Your server is yours and security will live or die by how you configure it.
Should always be posted when mentioning databases
http://xkcd.com/327/
The best security is one that admits that it can be defeated, a layered approach is best. After they've hacked the webserver where can they go from there? your SQL server will be wide open.
Consider using a grsec patched kernel, chrooting your webserver and restricting everything that isn't absolutely necessary. Grsec supports the feature to prevent binaries from executing on a specified chroot, this may prevent many attacks that would escalate their access. Don't provide compilers, don't have perl/ruby/etc available unless you need to. They may be able to penetrate with a staged payload dropping the privilege escalating exploit at the end and in this case the chroot may restrict their access. If they do manage to break past the chroot you want a fully configured RBAC system. Root shouldn't mean ring 0 in most cases. Disable loading kernel modules, disable /dev/kmem access, disable write access to boot directory and require password at reboot (this prevents them from loading a new unrestricted kernel).
If you can afford it put a bridged firewall/IDS between the webserver and the database. Log everything, make sure your alerts work! Alerts are extremely important in that you can detect a hack in progress and possibly prevent further data extraction! Use white-listing instead of blacklisting. Only allow the absolute minimum. The idea here is that you want to reduce your attack surface as much as possible whilst still keeping functionality.
That is just on the IT aspect tho. Consider the scenario in which an employee goes rogue: disable firewire port (DMA attacks are easily possible), disable usb ports, lock the server room, immediately lock out/revoke IDs to an employee about to be fired (preferably before they're fired), and for god's sake screen your applicants.
DO run all user-sourced input through "mysql_escape_string" or your DBMS' equivalent. Most DAO implementations already do this.
...and make sure to put user input in quotes (or back quotes) in the final query as even an escaped string can cause problems:
Basic query: "SELECT * FROM tbl WHERE x = ?"
Input: "1 OR 1=1"
Final: "SELECT * FROM tbl WHERE x = 1 OR 1 = 1"
Only, chroot every service you provide that could be accessed over the network.
Prepared statements are a decent half-step, but they aren't easily applicable to variable-length queries such as "advanced search" or anything else with optional parameters.
I've generally managed this by dynamically building the query, preparing it, then dynamically building the data statement. Requires a little extra work, but I'll take it any day to mucking with various escape_string methods.
Code wise, I've found it makes it a little prettier to abstract the "search" from the SQL. So you have a "SearchComponent" object that contains say, field, comparator, value .. your advanced search is comprised of a collection of arbitrary SearchComponents.. you then iterate through this array when building your query (inserting the appropriate operation and token where appropriate) .. then iterate through the collection again when building your DATA statement. This works just as well for optional arguments.
negating what little advantage the prepared statements offered.
I strongly disagree with "little advantage". Personally I think decoupling query from data and essentially eliminating most injection attacks and escaping/formatting nightmares is a pretty substantial advantage. Plus you get a performance boost when executing the same insert query over and over.. as it can cache a lot of the execution plan.
DO make your database operations into stored procedures and only give your database user the execute rights on those procedures and NOTHING else
As opposed to what, mister? Writing SQL in PHP?
Perhaps I'm trolling, perhaps I'm not.
Dont do anything to piss off a vengeful hacker collective.
Lemme draw some parallels to home burglary. Your opportune thief is going to look at one or 2 attack vectors. If he cannot get in he'll move on. Contrast this with a professional burglar. He'll watch a target for days, weeks or months all while taking precious notes about weaknesses in security like a time of day where the property is unguarded or maybe a fault in your automated garage door. He's determined to get inside for something and eventually he will. It's far better to be shrugged off by the opportune thief than grab the attention of the professional burglar.
Truth be told, you're going to forget something or there will be an attack vector you simply cannot do anything about. There's no such thing as 100% secure. I'd rather be a target for a script kiddie whose exploiting known and patched holes than piss off a group of dedicated hackers who do their own pentests and wont give up til they've found something to bring you down.
Easy -
Request, log, and record, only that information that is absolutely necessary and nothing more, and keep it only for as long as you'll need it and not a bit longer.
You can save yourself some heartache by not storing any PII and PFI.
Don't store payment information.
Don't store credentials. Consider using OpenID or Google or (shudder) Facebook Connect for accounts.
Keep sensitive information off any internet-accessible systems.
And last, don't trust any input from your visitors.
Sanitize all input.
Declare all variables.
Don't assume anything.
If you're expecting an integer, make sure you convert the submitted form data to an integer for that variable implicitly.
Same for dates, strings.
Normalize all input.
Sanitize all input.
Never trust any input.
Consider using a database abstraction library with well documented and mature APIs. Don't code things yourself.
Don't turn on ssh password authentication. Require only public/ private keys.
Turn register globals off in PHP. Use safe mode.
Make sure MySQL is on a separate server, with an RFC-1918 address, accessible from a dedicated NIC that is not on the Internet.
Consider a security audit and professional code review if you're planning on taking any money.
Draw out the communications architecture of your system and only allow those communications paths that are necessary. For example, users won't need to send packets to database servers.
Look through the OWASP guidelines, make notes, and do a thorough code review. No matter how secure the systems are, the application must be secure too. There is a lot more knowledge out there on securing OSes and Web Servers, leave that to your hosting company. You need to concentrate on your application.
Consider the scenario in which an employee goes rogue: disable firewire port (DMA attacks are easily possible), disable usb ports, lock the server room, immediately lock out/revoke IDs to an employee about to be fired (preferably before they're fired), and for god's sake screen your applicants.
Beyond the many war stories, I went to a security conference back in 1999 (yes, that early) where the then-primary IT security guy for the Navy told us that in real-world penetration testing 'red team' exercises, the average cost to bribe a systems administrator to let you into the machine room and do whatever you want was just $7000.
It's easier to be a result of the past, but more fun to be a cause of the future! http://www.spacefinancegroup.com/
There's no damn hosting provider that will take care for you programs' security. You know why? Because they are *hosting* providers, not service providers. The service is up to you, and if you are not up to the service I really better prefer you just not trying./em>
Not really true... many good hosting providers are also service providers and can help with anything (for the right price), and that's a good thing -- because most web developers are not good system administrators, you the author of this website should probably not be the system admin, DBA, etc, all at once; hosting providers employ experts, and you should utilize available expertise, or host a dedicated option and get consultants to set everything up.
The security of your software implementation is your own business. The hosting provider's system administrators should work with you to ensure security of the platform the hosting provider is offering you that your software runs on, or offer you options that will ensure security.
They might recommend things like VPS on shared server, dedicated server, or colocated hosting, to mitigate multitenancy risks; most hosting providers have many options, for the security concerned. Or they may explain what measures they have taken to ensure the software is secure and kept up to date. In any case, they should be able to provide more than some silly seal.
It's always ultimately going to be up to the person hosting a site to decide how much security is needed, how sensitive the data stored by the application is, and what their own compliance requirements may be.
you can not store CCV2 ever, even if encrypted. Read PCI and try again.
You can actually get a decent colo fairly cheaply. I am paying $50/mo for my colo, which is a share of a 100mbit pipe with no bandwidth metering. For a low traffic site like the original summary is discussing, that's actually plenty.... it is certainly enough for my colo system, which is primarily a mail server, but also hosts a small low-traffic website and forum. Throw in $1000 for the hardware if you don't have an old server-capable computer kicking around, and you're golden.
And if your e-commerce site isn't turning enough margin to pay for a $50 colo, then you really shouldn't be running an e-commerce site in the first place. As your traffic rises, you can worry about expanding your infrastructure either with load-balancing multiple servers, or with moving your colo to a faster pipe.
Please do not tell people to use mysql_escape_string. That function is broken and does not escape proper.
Also, just because you need to dynamically construct a string doesn't prevent you from using prepared statements. Just need to make sure user input is always passed to the database through parameters.
That being said - don't use MySQL in the first place; handling customer data and especially billing information (OP says customer site) in MySQL is just asking for trouble. ( http://sql-info.de/mysql/gotchas.html - note this was written for 4.0 as it says, but a lot of them are still very much a problem today).
You should consider adding 2FA authentication token such as a Yubikey which has lots of great extensions or for more security a ShieldPass access card which has the mutual authentication capability.
What type of hosting are you getting? Shared hosting where you don't have the ability to do anything but setup a database, or you getting bare metal hosting where you can choose the OS and how to setup every detail of it, or you supply the hardware and routing equipment to a hosting facility . I suggest getting the bare metal or sending your own hardware, then using the docs you can get from the NSA on securing the servers. http://www.nsa.gov/ia/guidance/security_configuration_guides/operating_systems.shtml Like many people have said, make sure that you don't have direct access to the MySQL server from the outside, and that it only talks to the webserver to give data from the database. Even setup a management server where you can do WSUS and remote desktop stuff from if you are going Windows, or another Linux box that you can SSH into to then access all the other servers. If you do your own hardware you can supply your own firewall and setup VPN connection to it. Blah Blah Blah, you are getting the idea from what everyone is posting. So you should hopefully have a good starting point.
-----BEGIN PGP SIGNATURE-----
12345
-----END PGP SIGNATURE-----
> Poor programming practices opens you up to SQL injection.
Insecure programming practices, you mean. They're poor only in 99.9% of situations, i.e. where the need for security justifies the brief additional time. You may not need them, for example, in an in-house diagnostic script you're using for a small company that only two admins can use--provided that you are disciplined enoight not to let that spill over into your more secure coding.
-- IANAL, this isn't legal advice, and definitely isn't legal advice for you. Also, Squee!
Do NOT have 'sony.com' as part of your sites name.
Who would win this election: Andrew Weiner vs Andrew Weiner's weiner.
The OP specifically mentioned that he is in a hosted environment. So any pen testing he is doing at the OS level or against a multi-teneted MySQL environment means that he is very possibly committing a crime unless he seeks permission. Testing your website it self for vulnerabilities might be safe waters, running an aggressive Nessus scan against the server could be construed as attempting to breach 50 other websites and their databases.
Bingo. 90% of SQL injection prevented, right there.
If you really need to do this, create a white-listed array of tables it's OK to access in this manner and check the input against that before running the query. Also useful if you want user input to select a class/method to use/execute. That's basically what front controllers for many web frameworks do.
EXEC's pretty handy. Damn near necessary, IMO. Pretty safe, too, as long as the rest of the permissions are locked down.
Next, think about whether you need reversible encryption. If you're just validating passwords, use a one-way function. Similarly, if you only need the data for infrequent audit or forensics, you can encrypt it asymmetrically, where the system does not contain the private key. (Secure the private key somewhere else for emergency use.) The data goes into a black hole unless you manually intervene.
The real problem with shared hosting (virtual or otherwise) means you have to trust the real host not to let someone else at your raw data. Since the real host can see into all the virtual machines, you have to trust it and secure it as well. If your not doing that, who is?
Best way, hire a good 3rd party auditor sign an NDA with them. You get another set of eyes on the setup. Plus they will use a number of tools to scan your product and the servers you host it on that you may not have easy access to. For example, IBM's AppScan is designed to scan web applications and test for SQL injections, XSS vulnerabilities, etc.
At some point you may want to look at purchasing a copy of AppScan, however that would all depend on how often your code/environment will be changing. WatchFire was recently (last couple of years) purchased by IBM, which is how they acquired AppScan. I've tried most of the tools out there, AppScan is light years ahead of any others and it's priced that way too.
Good luck!
And I'll check it out for you...
If you're holding customer credit card info, you'll need to meet PCI compliance regs. If you're not, you should look at PCI compliance regs anyway, because they're a good guideline.
Then, when that has scared you enough, wake up look up prepared statements, and then don't use MySQL, especially if you are using PHP. Views don't work properly, subqueries bite, and you can't have joins in a delete statement that makes doing compound deletes virtually impossible without serious pain and suffering. If you were planning on using Amazon RDS, know that if you're tables are MyISAM based, the backups don't work.
Have a nice life.
Everyone is living in a personal delusion, just some are more delusional than others.
If you don't own the iron you can't stop anybody who does doing anything they like with it. Even if you can trust them (and you shouldn't even contemplate it if you don't) you have to rember the warning that was put in big letters on the QEMU web site years ago - "virtualisation is not security". It can't be trusted with full seperation as much as Solaris zones or even different user accounts on the same machine because security was never the aim and is only an afterthought. If somebody else is running their stuff in a virtual container on the same machine there may be flaws that can give them access to yours, since less thought has gone into preventing that than seperating the users on a simpler multi-user system. The odds are that you would have to be very unlucky to have somebody malicous and aware of such flaws on the same hardware as your virtual machine - but it's going to happen to somebody somewhere and is likely to get some press and get people asking you questions when it does.
Then there's the simple resource issues where somebody else on the same box could be hammering the disk or taking all the bandwidth.
Your own box in somebody else's rack is a different story. If you can trust everything on it, virtual machines or not, then the only others you have to trust are the people with keys to the door.
Little Bobby Tables
"The Most Fun Possible on 4 wheels" is at SunBuggy in Las Vegas
Prepared statements are a decent half-step, but they aren't easily applicable to variable-length queries such as "advanced search" or anything else with optional parameters. It's far too easy to hit one of these walls and fall back into sloppy coding to get around it, negating what little advantage the prepared statements offered.
I don't like prepared statements for the very same reasons. For this reason, we've built our own prepared-statements-like tool that gives us the same advantages of a prepared statement without requiring us to register the statement first.
A preprocessor takes two inputs: the query with string variables embedded, and an array of inputs to match the string variables. In PHP:
$sql="select lastname from users where login = '@login'";
$vars = array('login' => $_REQUEST['login']);
$exec = PrepareQuery($sql, $vars);
The PrepareQuery() function looks for the variables in the sql and replaces them with values passed in, properly sanitized. (DB_escape_string(), etc) The result is very robust and also allows for very dynamic use such as dynamically created queries with optional values, etc.
I've yet to run into a scenario that this model didn't easily handle.
I have no problem with your religion until you decide it's reason to deprive others of the truth.
There are some automated tools like skipfish . They help finding possible problems but can't replace the eyes of someone with security expertise looking over the code and setup.
Have you considered using Opa? I may be biaises on this topic (I'm a member of the Opa team), but it sounds to me like it's a very good match for your issue. It's an open-source web development platform designed for security - it's an Owasp project, btw. Among other things, it guarantees that your application is invulnerable to XSS and SQL injection, and it performs a large number of analyses on your code, on the inputs, etc. to greatly improve security.
Depending on the current status of your code, you can either use this as a foundation for the whole application, or just as a front-end.
More info on the teaser website, on my blog, or on IRC (freenode, channel #opalang).
[...] get consultants to set everything up.
You can't rely on consultants for security that way. At least not just for "set up".
Security is a continuous processs. Not a thing you do just once.
Prepared statements give you performance too (the DB server caches query optimizations), which your custom solution does not.
Also you are dependent on your PrepareQuery() code to evolve with the SQL features/quirks of the database. And if the DB_escape_string() function is not implemented by the server side of the DB server, you can't rely on it (differences between client driver and server implementation are things that can be exploited for SQL injection). So this is the way towards failure.
One thing to check is the userid that your application code (php, jsp or whatever it is) runs under... Many shared hosting providers run all this stuff under a single shared user, which means that user needs to be able to read things like your database config including password... So if someone compromises another customer, they now have the ability to read all your files...
http://spamdecoy.net - free throwaway anonymous email - avoid spam!
The hosting company is the apartment complex. All they do is allow traffic to your door.
;)
What you do in the apartment is your concern.
You may wish to involve a web programmer, or learn a whole bunch.
-rant-
If the site will be taking money, beware PCI compliance. Experience shows most of the companies offering this "service" are just scammers. Just last night one of my sites failed due to alleged existence of a file that in reality is not even on the server. Not even the directory exists, yet it was flagged for this brand new "critical problem", and supposedly Visa can financially penalize the client due to "failure".
They're mostly a bunch of lazy crooks cashing in on FUD.
-/rant-
Good advice previously.
In general, if you aren't the sole admin user on the box, you shouldn't play. You can co-locate, sure. But you must be the person who is responsible for everything on that box. The ONLY access the co-location provider should be able to have is the ability to execute a shutdown script to protect themselves from your rogue processes.
If you are not the sole owner, then you are dependent on their security being up to snuff.
If your application is small, you may be able to work with a virtual cluster of machines running on a single box.
I would give serious consideration to encrypting all sensitive information in the database. Even if the keys are wired into the application, it means that data extraction has to work through the application to get data.
I would also give serious consideration to putting large quantities of meaningless information into the database allong with some means of filtering for your own use. A Black hat who gets 2 million email addresses from your machine, but finds that 99% of them are bogus will not earn the gratitude of his client.
Third Career: Tree Farmer Second Career: Computer Geek First Career: Teacher, Outdoor Instructor, Photographer.
So, from what I saw, you're asking about the security of the MySQL backend, which is the place where the hosting provider has the most control and you have the least. All the talk about hardening standards that you should read up on is rubbish; you don't get to harden the systems, they're already as hard as they will ever be (whether hard or not) because of the way the hosting provider has provisioned the system. So what you're really into is a situation where you need to know how to spot a secure architecture and good standards, and then get them to show you their architecture and provisioning standards so you can see for yourself how solid they are.
All the talk about PHP hardening, pen-testing, etc. is fine, but the main concern I would have is about what happens if someone gets to their backend database(s) via someone else's insecure website...becuase that website exists today among their customers, has been there already, and will continue to be there in the future. What protections are there to ensure that an attacker who gets through to the database backend of "Insecure Website Inc." won't also be able to leverage their way laterally to your backend? This is as much an architectural design question as a security hardening standards question; both come into play. I'd look for things like reuse of passwords (if they provision every MySQL database separately, are there any credentials that are common to all of them?) and ways they make sure that getting control of the database won't result in gaining access to the things like the underlying operating system or provisioning infrastructure.
Oh, another thing...the security guidelines that a lot of people are bandying about in earlier responses aren't necessarily enough. There are a whole set of other concerns for a multitenant environment, as found in a hosting center...so make sure that whatever you work with contains that bit of awareness. They'll call it out explicitly, if they cover it.
For your security, this post has been encrypted with ROT-13, twice.
While any server that is not completely within your level of control opens up possibilities of having it compromised, there is also no 100% guaranteed secure configuration that you could do even if it were 100% in your control. I would knock out the obvious first by doing a port scan on the server address to see what services may be running that aren't needed. Also make sure that MySQL is bound to the loopback IP and not the public IP (unless you have multiple servers accessing a central database server, in which case setup SSH secure tunnels with permission restrictions limiting only those servers - although it would be better to just install a second NIC on each server and also run a private network link between the servers). Code wise, I'd make sure that you are validating all submissions and are protected against SQL injection attacks. You can also change settings in PHP to be restrictive in memory usage, file upload size, and handling of requests by setting the minimum required value that your code base would need or use. This can be done in the Apache virtual host configuration, if they don't want to use those settings globally on a shared server. Lastly, when all else that can be done is handled, make sure to encrypt any sensitive data in the MySQL tables. Sure, if the server is compromised, the hash key string or other methodology key is contained either in the code base or in the unique key to the MySQL install, but it's one additional step and would require them to have much more data downloaded - which if nothing else, buys you time that they would need and for you to find them in the process. Oh, and depending on if your running in your own chroot setup, you can use non-standard ports for services like MySQL. Let's face it, the majority of hacking is done by script kiddies that are executing code or things they don't even fully understand. Protecting against the other 5% is a bit more involved, but also unlikely if you protect against the common automated attacks.
Good luck with your new site, and hope you have great success. If you take pride in your product, regardless of what it is, and make it as well as can be made and sold for a fair price - you may not make a boatload of cash overnight that screws the consumer like every other company in the world, but you will have steady and long lasting profit, as well as providing a value to the world. At least that's my two cents on a world with declining business ethics. 8-)
1. MySQL SQL injection. Every single parameter fed to the database needs to be run through the mysql_real_escape_string function. To be future proof, queries should be sent as prepared statements. If you don't know what this stuff is, go to php.com and start reading. mysql_real_escape_string() is a good stopgap measure you can easily implement to scrub your parameters, however, long term you should be using prepared statements. Prepared statements tell the database "This parameter is to be treated as data and not interpreted as SQL". They separate the meat from the milk so to speak. This is the future proof way to secure your SQL queries. Stored procedures do NOT secure your code simply by being stored procedures, although, strongly typed input helps a great deal. No matter what you will be accepting strings/char etc in your database and that's where you'll be vulnerable. Prepared statements when used within stored procedures help, but you can SQL inject your way out of a non-prepared stored procedure call too, even if the sql within is a prepared statement. Make your stored proc calls with prepared statements, then the SQL within the stored procs should also be prepared statements. Do some reading about this stuff. Read it til you understand.
2. XSS. Every variable you get from GPCS (get, post, cookie, session) or database should be wrapped with htmlentities() before display on a web page. This prevents people from phishing your users by neutralizing javascript code they may try to inject. Javascript will simply display on your page and not get executed, making it harmless. If your regexes aren't the greatest, javascript can be sent to your db, then displayed as content. That's why even if it's coming from your db, you should htmlentities() it before displaying it.
3. Scrub your input. Input should only consist of printable characters. scrub it before processing to remove binary data, nulls and other potentially harmful stuff (unless you are handling binary such as a file upload or something). There are regex recipes all over the place for doing this for removing javascript, sql etc. None of them are perfect and that's why you absolutely must adhere to rules 1 and 2. You should also limit the length of the input to prevent buffer overflows that your scripting language people may have missed in their language.
Naturally the usual stuff about securing your server etc apply. Admins are really good at this stuff. However the average off the shelf app will have a lot of vulnerabilities. Almost all of them will be one of the 3 listed above. They are easily fixed. The hard part is finding them. Use grep.... look for "insert, GET, POST, update) etc and other keywords related to sql inserts, updates, delete, create and select.
If the app you are thinking of using doesn't do this stuff, walk away. Find another one. It's also good to force your users to use strong passwords and all that other stuff people mentioned, but you can have the most secure box in the world but if the application running on it is insecure, you will be pwned.
Security is more than just web app security but web app security is where 99.9999% of FAIL occurs and 99% of that happens in items 1-3.
Don't kid yourself. It's the size of the regexp AND how you use it that counts.
Well, the short answer is that if you're in a shared hosting environment, you probably can't do much and in that situation I probably would not recommend storing sensitive information. Assuming you are on a dedicated server or VPS, you can secure your server, but what you need to worry about is what type of security do they have in the network as far as IDS/IPS, network segmentation, and firewalling, as well as what type of physical security they have. I.E. where are the machines physically located, who has access to them, are they under NDAs, what type of background checks have been run on these people, etc. Unfortunately, the truth is that a lot of this stuff may be spelled out in a service agreement, but it may not actually be practiced. If you care about CYA, then get it in writing. If you actually care about not having a breach so you can keep your customers, then the answer is probably something more along the lines of host it yourself in a secure physical environment, or colo a box that you own at a place that you trust, do not give root priviliges to the colo provider, and hash/encrypt the sensitive data on it.
If you must script, NEVER EVER concatenate SQL. If no ORM is availble, use whatever languages parameterized SQL scheme.
I'm looking for an easy-to-use alternative to concatenation in cases like these. For the example, the right side of SQL operator IN is a 1-column table:
But some DBMS APIs do not support table-valued parameters, only scalar-value parameters. I could parameterize the values in the table on the right side of IN, but only if I have to know in advance how many placeholders to use (for example, username IN (?, ?, ?)), and I almost never do. So without concatenation, how do I build the right side of an SQL IN expression? Or do you recommend CREATE TEMPORARY TABLE with one column, executing a parameterized statement to INSERT values into this table one at a time, and then using this table as the right side of an IN or JOIN?