A system never can never be totally safe. When talking about security keep in mind that is all about raising the bar to ambitious intruders, and keeping your system as clean as possible. You can never have an absolutely secure system.
Below I appose the basic security measurements that you have to take care of, to feel safer.
SSL(Secure Sockets Layer)
Both the old SSL and the it’s evolution TLS(Transport Layer Security) referred as SSL. These are cryptographic protocols which crypt the data that is transferred through a computer network. They operate after TCP/IP(Transfer Control Protocol / Internet Protocol) and before the application layer(http, ftp, imap).
Buying an SSL certificate is of vital importance if you want to implement sessions in your app.
Files should have the correct permissions in order to prevent attackers to read/modify files that they shouldn’t. 4 is readable 2 is writable, and 1 is executable for files/directories. You should cmod your files differently if you are using a shared server. Here is a recommendation that I read about:
my server files 664, folders 655, config.php 660
my shared server files 644, folders 755, config.php 600.
It’s better not to be easy for an intruder to find if you are using PHP (and the version) information that are send with the headers.
You can turn off expose_php from your php.ini file.
You can configure your web server to parse different filetypes through PHP. These files are gonna be php files but with different suffix (e.g index.rand). This can be made in .htaccess, or in the apache configuration file.
An attacker might feed your system with improper data to check the kind and the context of the errors that are returned. To hide the errors you can do one of the following:
scrutunize all function, and attempt compensate for the bulk of the errors.
disable entirely error reporting by error_reporting(0), or by setting display_errors to off in your php.ini file. You also have to define a path to your log file using error_log ini direcive and turn on log_errors.
Use PHP’s custom error handling.
Never connect to the db as its owner or a superuser. You may create different db users for every aspect of your app.
Encrypt data(especially passwords) before inserting it into the db and decrypt it when retrieving it.
Use prepared statements with bound variables.
Check if the given input has the expected data type(is_numeric(),ctype_digit()). You can silently change its type using the settype(), or use its numeric representation by sprintf().
If the db layer doesn’t support binding variables, then quote each non numeric user supplied value to the db with it’s db-specific string escape function(e.g. mysqli_real_escape_string(),sqlite_escape_string() etc).
Do not print out any db specific information especially about the schema.
You may use stored procedures and previously defined cursors to abstract data access so that users do not direclty access tables or views.
By enabling session.use_strict_mode uninitialzed session ID is rejectd and a new session ID is created, if a save handler supports it.
By enabling session.use_only_cookies cookies must be uncoditionally enabled by the user, or sessions won’t work.
You can use session_regenarate_id(). It must be called periodically, and must be called prior to set authentication information to $_SESSION superglobal. Never call session_regenarate_id(true) and session_destroy() for active sessions. Do not prohibit access to old session data immediately.
Set and manage expiration time stamp in $_SESSION. Prohibit access to absolete session data. When absolete session data access is detected remove all authentication flags and force the user to re-authenticate. This is a possible attack.
Let session_gc() to remove obsolete data.
Use read only sessions when session data update is not required. Use session_start(['read_and_close=>1']);. Close session as soon as you finish updating by using session_commit().
Auto login key must be able to be used only once. You must also implement a feature(checkbox) that disables auto login.
Chooce the smallest possible value to session.gc_maxlifetime.
My guide to write this article was the official php’s manual which has plenty more information!