Protection of PHP scripts from analysis and modification. Use a unique administrator login

All software products to protect PHP scripts are divided into two categories: those requiring installation on the server additional modules and working with the usual configuration of web servers. The former are more reliable in terms of security, since they convert PHP scripts from text form into special binary code, but require access to the server with administrator rights. The latter can work on almost all hostings with PHP support, including free ones, but are not very difficult to hack. Source code that does not use encryption or compression can be divided into a separate subgroup.

Server-level protection:

Zend Encoder / Zend SafeGuard Suite - the most popular commercial protection, modules for Zend support are usually installed on all paid hostings. Zend provides binding of scripts to domains and ips, setting the trial running time of scripts and powerful obfuscation. All operating systems are supported. There are several versions of utilities for removing Zend in the public domain, all of them are modified PHP versions 4 and 5. Old versions of Zend can be removed without problems, but in the latest versions difficulties arise due to obfuscation of the source code.

New, actively developing commercial protection. At the level of its own API, it provides interaction with protected scripts, operating Windows systems and Linux. Due to its low prevalence, it is not installed on conventional virtual hosting, but can easily be installed by users on dedicated servers. There are no public decoders.

Commercial protection is practically never found and is not installed on virtual hosting. Allows you to set a trial period for running scripts with date checking by external servers exact time, link protected scripts to servers, IP address, MAC address network card, and this data is used for decryption. All operating systems are supported. There are no public decoders.

phpSHIELD. SourceGuardian for PHP prototype. After the merger of two developers, it stopped developing as an independent product. The main functionality is the same, there are no public decoders.

ionCube PHP Encoder. The second most popular commercial product for protecting scripts. After the appearance of public decoders for Zend, it began to be increasingly used and installed on virtual hosting. Allows you to encrypt not only scripts, but also templates, xml documents, images, binary files. Links protected files to servers, has a powerful obfuscator, and supports all operating systems. There are no public decoders, but in some cases it can be removed by deZender.

PHTML Encoder. A rarely used commercial security system, it provides the usual functionality for products of this type, works under all operating systems. For an additional fee, you can purchase source security codes and modify them to suit your needs. There are no public decoders.

DWebEncoder. Exotic protection for Windows, designed for creating scripted presentations and catalogs on CDs. When installed, it is something like an independent web server on which encoded PHP scripts are executed. There are no public decoders.

PHP Compact. The defense is more theoretical than practical. It was developed at one of the domestic forums, but it seems that the matter has not progressed further than the author’s releases. There are no decoders, as well as protected scripts.

An open source addition to the legacy PHP accelerators Turck MMCache and eAccelerator. Translates scripts into bytecode in order to increase the speed of their execution. There are versions of modules for Windows and Linux. There are no public decoders, but it is possible open source the project will somehow help in studying.

Source code level protection:

PHP LockIt! . Popular commercial protection, found very often, mainly on scripts of foreign developers. Allows you to set a trial period for scripts, binding to domains and IP addresses, compresses scripts regular means php (gzinflate). The only difficulty is a good obfuscator. Various versions protections differ only in the modification of the unpacking module. Easily removed both manually and automatic mode. Without an obfuscator, it is removed exactly to the source code; with an obfuscator, it requires additional processing.

CNCrypto. There is not even a demo version available for free access; the analysis was carried out using protected scripts. The plug-in module is not difficult to unpack; protection relies only on good obfuscation of the source code.

PHPCipher. Protection is an online service. An archive with your scripts is uploaded to the site and the already protected one is downloaded back. A paid license allows you to sign protected scripts with your data and use them for commercial purposes. Free license allows use only for personal needs. The protection itself is a Zend-protected PHP module that connects to protected scripts. After deZend, the protection module and obtaining all the necessary constants from it are removed completely to the source code. There is no obfuscator function.

ByteRun Protector for PHP. A commercial product, depending on the license type, allows you to protect scripts both at the server level and at the source code level. Server protection with standard features, nothing special. Protection at the script level can be removed very easily automatically and manually. There is no public decoder for the server version.

Very popular with domestic developers protection. It is a security module heavily littered with empty code, which is connected via include to protected scripts. The decoding algorithm is very simple and does not cause any difficulties in manual or automatic removal. In all cases, it is removed completely to the source code, there is no obfuscator function. There are small features for special cases of decoding, but they will not be described here.

CodeLock. Another popular defense, an excellent example of illiterate programming. It is an application in PHP that allows you to encode both the scripts themselves and the result of their work in the browser using javascript. Scripts can be protected with a password, but due to the incompetent implementation, the password can be easily found out even without removing the padded protection. The protection module is a PHP script littered with empty code that connects to protected scripts. The protection algorithm is very simple; it is removed completely down to the source code. There is no obfuscation function.

TrueBug PHP Encoder, more recently TrueBug PHP Obfuscator & Encoder. A very interesting protector to explore. Before version 1.0.2 used standard means php for gzip compression, starting from version 1.0.3 the authors developed their own compression algorithm. The new TrueBug PHP Obfuscator & Encoder product adds obfuscation and source code optimization functionality. The only thing weak point protection - an unchanged algorithm for decoding scripts, but the algorithm itself changes for each version of protection. After parsing, the protection is easily removed exactly to the source code, of course, provided that an obfuscator was not used.

Zorex PHP CryptZ. Protection, like CodeLock, is a PHP application and requires a MySQL database to operate. The protection module is a plug-in script in PHP, encrypted in several layers. After parsing, the algorithm can be removed very easily exactly to the source code. There is no obfuscator function.

Free PHP Encoder. Free online service for coding PHP scripts. The protection module is a plug-in PHP script covered with Zend, which must be downloaded from the website. After removing Zend and parsing the algorithm, the protection can be easily removed completely down to the source code. The protection algorithm is unchanged, there is no obfuscator function.

Script in PHP, primitive encoding, standard base64. It does not deserve more attention and is not of practical interest.

“Bank sites are broken for the sake of money, the Pentagon is broken for the sake of espionage, and no one needs my project,” unfortunately, this is exactly what most owners of personal blogs, online business cards, and virtual representative offices of small companies believe. Only a few people think about how to protect a website, but in vain. In modern realities, absolutely any platform, regardless of type or popularity, is of interest in the eyes of hackers. Who might need your resource and for what? Let's figure it out:
1. Scriptkiddis pranks. The jargon refers to novice hackers who are taking their first steps into the “dark side.” Having acquired several tools, or having written a couple of their own programs, they are eager to test their performance on the first victim they come across, and, as a rule, choose the easiest (weakly protected and not updated CMS) targets.
2. Black SEO. The services of dishonest optimizers are still in use - placement hidden links in the code of projects with a TCI of more than 10, this is still practiced. And, first of all, resources on open-source engines come under attack. source code(Joomla, Drupal, OpenCart and so on).
3. Building a botnet. Protecting WordPress using htaccess and plugins is also relevant because absolutely any resource can be used to create a zombie network used in DDoS attacks, spamming, etc.
4. Collateral damage. Finally, you may not be attacked - the main target will be hosting, and the site will serve only as one large vulnerability in the provider’s IT infrastructure. Of course, his fate will be indifferent to hackers.

The consequences of hacking can be the most unpleasant: loss of content, or the resource as a whole, pessimization in search results search engines, loss of audience due to the inscription “The site may threaten the security of your computer or mobile device”, and even the risk of becoming involved in a criminal case if illegal actions were committed on the basis of your web resource.

This means that we can say with confidence that security issues affect absolutely every webmaster. And if they are neglected, all efforts to search engine promotion(and this is money and precious time) can go to waste overnight. The problem is very relevant, so I decided to start a series of articles devoted to network threats and methods of combating them. In three issues the popular CMS system- WordPress.

Methods for protecting a WordPress site

One of the most primitive hacking methods is brute force. The term literally translates as “brute force”, and means obtaining a login/password pair using a brute-force method possible options. Often, brute forcers try to make their lives easier by taking advantage of errors in the engine and server settings - this helps them, for example, find out the account name, which significantly reduces the number of combinations. It is the elimination of these vulnerabilities, as well as methods of combating unauthorized access attempts, that will be discussed.

1. Use a unique administrator login

By default, the system prompts you to create a user named admin. However, in order to protect the site, WordPress is better Just use a login consisting of a set of random letters and numbers. On an active resource, you can change the administrator name without any problems using one of two methods:

Through the admin panel. Go to the “Users” section, click the “Add new” button and create account. In the “Role” field, select “Administrator” and confirm the operation. Then log in as the newly created account, return to the “Users” section, select “admin” and click “Delete”. In the window that opens, set the radio button to the “Link all content” position and select a new administrator from the drop-down list, and then click on “Confirm deletion.”
. Using phpMyAdmin. It is much easier to carry out the same procedure through the database control panel. Select the required database, find the wp_users table, find the line “admin” (ID=1), click on “Edit” and enter the desired name.

2. Create a special account for publications

If you don't expose the administrator, this will provide additional protection. Create a separate account for posting articles and link all previously published materials to it in the manner described in point 1. Next, add information and communicate with readers only from the new account.

3. Set a complex password

Follow generally accepted guidelines: the password must be at least 10 characters long, it must be unique and consist of a random sequence of upper and lower case letters, numbers and special characters.
Under no circumstances should you:
. create a password from meaningful phrases
. use any factual data (date of birth, maiden name, bank account number, current year...)
This will eliminate the risk of selecting a passphrase from a dictionary, and will also significantly increase the time required for brute force. So, cracking a sequence of 10 characters consisting only of lowercase letters and numbers (hki458p1fa) will take 10 days of computer time for one PC, but it’s worth adding capital letters And additional signs(Nv6$3PZ~w1), as this period increases to 526 years, guaranteeing almost absolute WordPress protection. Coming up and remembering such passwords is quite difficult, especially if you oversee several projects. Therefore, to generate and store them, it is better to use special managers, for example, KeePassX, which is distributed free of charge, or a regular test document (it is better if it is packed in an archive with a password).

4. Change your database password

The rules listed above also apply to MySQL access code security. After all, it is there that all the content is contained, as well as the hash of the admin’s secret phrase. If you already use a weak password, you should consider changing it. This is done as follows:

1. Go to the phpMyAdmin control panel
2. Open the “Users” tab and select the database owner
3. Click on “Edit Privileges”
4. Find the “Change password” column and enter the new secret sequence in the appropriate fields
5. Save the changes by clicking on “Ok”

Now all that remains is to edit wp-config.php, otherwise WordPress will not be able to connect to the database. Find the line define('DB_PASSWORD', 'password'); and enter New Password instead of the word password. Note that because the (') character is used to delimit SQL commands, it should not be used as part of a secret phrase.

5. Update passwords regularly

They should be changed at least once every six months. An extraordinary change of code phrases MUST be carried out after:

Transferring authentication data to third parties (programmers, system administrators, optimizers, and other specialists, even if they work on the staff of a hosting company)
. logging into a web resource from someone else’s computer (at a party, in an Internet cafe)
. authorization from equipment that may have been compromised (a machine infected with a virus)

6. Don't forget to change the secret keys for cookies

They are located in the wp-config.php file. There are 8 of them in total:

define ("AUTH_KEY" , "unique key" ) ; define ("SECURE_AUTH_KEY" , "unique key" ) ; define ("LOGGED_IN_KEY" , "unique key" ) ; define ("NONCE_KEY" , "unique key" ) ; define ("AUTH_SALT" , "unique key" ) ; define ("SECURE_AUTH_SALT" , "unique key" ) ; define ("LOGGED_IN_SALT" , "unique key" ) ; define ("NONCE_SALT" , "unique key" ) ;

define("AUTH_KEY", "unique key"); define("SECURE_AUTH_KEY", "unique key"); define("LOGGED_IN_KEY", "unique key"); define("NONCE_KEY", "unique key"); define("AUTH_SALT", "unique key"); define("SECURE_AUTH_SALT", "unique key"); define("LOGGED_IN_SALT", "unique key"); define("NONCE_SALT", "unique key");

As you can easily guess from the names of the variables, the keys are responsible for encrypting cookie files (a well-known jargon: cookie, salt, we feed hackers with salty cookies), which are used to ensure that the site “remembers” your computer after authorization. The bottom line is that even if an attacker gets his hands on the admin password hash, he will not be able to generate the cookies necessary to access the site without the listed secret phrases.

To improve security, default character sequences must be replaced with unique ones immediately after CMS deployment. For convenience, the developers have created a web generator located at www.api.wordpress.org/secret-key/1.1/salt/ - when you log in, the keys will appear to you, and if you refresh the page, the combinations will be updated.

7. Double authorization for the admin panel

Htaccess allows you to further protect your WordPress site by adding server-level authentication. The code will look like this:

< Files wp- login. php> # Set the basic authentication type - this means that when you try# when accessing the specified directory or file, you will be prompted for a password: AuthType basic # Enter the text that will be displayed in the form title: AuthName "Identify yourself" # Specify the path to the file containing the passphrase: AuthUserFile "/home/site/.htpasswd" # We indicate that when accessing the wp-login.php file, you must enter a password: Require valid- user # Deny access to the .htpasswd file to third parties:< Files . htpasswd>order allow, deny deny from all

# Select the authorization script file: # Set the basic authentication type - this means that when you try to # access the specified directory or file, you will be asked for a password: AuthType basic # Enter the text that will be displayed in the form header: AuthName "Identify yourself" # Specify the path to the file containing the passphrase : AuthUserFile "/home/site/.htpasswd" # We indicate that when accessing the wp-login.php file, you must enter a password: Require valid-user# Deny access to the .htpasswd file to third parties: order allow, deny deny from all

At the same time, it would be nice to take care of the security of htaccess itself. Strictly speaking, such a directive should be specified in the basic hosting settings, but given the carelessness of some providers, it’s worth playing it safe:

Instead of “login” we substitute the desired name. All that remains is to generate the password itself, as well as encrypt it, because storing such data in clear text is an unaffordable luxury. There are a lot of services for this, but it is better to write the necessary script yourself. This is done as follows:

1) Create a file with a .php extension in Notepad, for example, crypt.php
2) Enter the code there, replacing the word “Password” with the password you created:

3) Save the file and upload to the root directory
4) Follow the link site_name.ru/crypt.php - the password hash will appear on the screen
5) Save this value in the file .htpasswd, and upload it to the root directory, and delete crypt.php

The final touch is to prohibit viewing the contents of the web resource directory. It is enough to add a single line to htaccess:

Options All - Indexes

Options All -Indexes

This is done so that hackers cannot find out which files are located in the project directories. On many hosting sites, this directive is already included in the server settings, but if this point is overlooked, it’s worth adding it yourself.

8. Install captcha

Using captcha will allow you to cut off, if not all, then at least most of the brute force bots, and at the same time. The catalog of plugins for securing a WordPress site offers many options. In addition to connecting a proprietary solution from Google, Captcha by BestWebSoft of mixed type (graphics and text), which is based on mathematical operations, is of great interest. Independence from services, clarity and an acceptable level of complexity make the module one of the best.

Setup is not particularly difficult. The “Basic” tab allows you to select where the captcha should be displayed, as well as specify a title and symbol to mark required fields.

The “Advanced” section provides the ability to create your own error messages, as well as activate additional packages images to make life even more difficult for bots.

Another useful feature is a built-in white list of IP addresses for which the captcha will not be displayed.

The result of installing and activating the plugin will be the appearance of a form on the authorization page:

9. Change the admin address

When talking about how to protect a website on WordPress, it is worth mentioning a more radical, but also more complex method - changing Page URL authorization at the script level. The procedure is carried out in several stages:

1. Rename the wp-login.php file. Use a random sequence of lowercase Latin letters, numbers and dashes. For example: abc-123.php
2. In the resulting file, find all references to wp-login.php and replace them with the new name.
3. For correct operation site replacement must also be done in: wp-activate.php, general-template.php, post-template.php, functions.php, class-wp-customize-manager.php, general-template.php, link-template.php , admin-bar.php, post.php, pluggable.php, ms-functions.php, canonical.php, functions.wp-scripts.php, wp-signup.php, my-sites.php, schema.php, ru_RU .po

After these manipulations, the admin panel will be located at site/abc-123.php. Access to the new file should be limited and password protected as described above. You can also fool potential hackers by creating a fake wp-login.php file and also setting a password for it.

An even simpler option is to use the “Rename wp-login.php” add-on. After installing the site protection plugin, a new field will appear in the “Settings” -> “Permanent Links” menu:

10. Specify the admin IP

Additional security can be provided if you have static IP address. By denying access to wp-login.php from any other computer except your own, you will make life much more difficult for hackers:

< Files wp- login. php>order deny, allow deny from all allow from 127. 0. 0. 1, 127. 0. 02 #Specify your IP addresses separated by commas

order deny,allow deny from all allow from 127.0.0.1, 127.0.02 #Specify your IP addresses separated by commas

11. Disable authorization errors

When brute-forcing passwords, an attacker will find it very useful to know that the entered data was incorrect. Such messages are displayed with each unsuccessful login attempt, and WordPress also reports what exactly was entered incorrectly, login or password. To get rid of them, just add just one line to functions.php:

add_filter("login_errors" , create_function ("$a" , "return null;" ) ) ;

add_filter("login_errors",create_function("$a", "return null;"));

To do this, select “ Appearance” -> “Editor” -> “Theme functions”. The code must be written after the opening tag

12. Use a secure connection.

To encrypt traffic between the user’s computer and the web server, there is the https protocol, the use of which eliminates the possibility of intercepting important data, in our case, identification data. To activate it, you first need to purchase an SSL certificate, which performs two functions at once: authenticating a web resource and encrypting transmitted information. You can obtain it from specialized centers or from a number of domain name registrars. For non-commercial purposes, it is enough to acquire a free entry-level certificate (these are offered by the company www.startssl.com). As for the installation process, as a rule, it is described in detail in the hoster’s help section.

Having obtained an SSL certificate, you need to configure redirection of the administrative part of the web resource to a secure connection. In the case of WordPress, this is done using the following construction:

< IfModule mod_rewrite. c>Options + FollowSymlinks RewriteEngine On RewriteCond % ( HTTPS) = off RewriteCond % ( REQUEST_URI) =/ wp- login. php RewriteRule (.*) https:

Options +FollowSymlinks RewriteEngine On RewriteCond %(HTTPS) =off RewriteCond %(REQUEST_URI) =/wp-login.php RewriteRule (.*) https://%(HTTP_HOST)%(REQUEST_URI)

You can also force the use of SSL certificates at the engine level. To do this, open the wp-config.php file and add after

define ("FORCE_SSL_ADMIN" , true ) ;

define("FORCE_SSL_ADMIN", true);

In addition, you can set a global redirect from http to https. For new sites, this approach is optimal, given that Google encourages secure projects, giving them some priority in search results:

< IfModule mod_rewrite. c>Options + FollowSymlinks RewriteEngine on RewriteCond % ( HTTPS) = off RewriteRule ^(.* ) $ https: //%(HTTP_HOST)%(REQUEST_URI)

Options +FollowSymlinks RewriteEngine on RewriteCond %(HTTPS) =off RewriteRule ^(.*)$ https://%(HTTP_HOST)%(REQUEST_URI)

13. Block intruders

If you detect suspicious activity from certain IPs, you should block their access to the site. This is done by analogy with the previous method. The difference is that the directives are written for the project as a whole, and we list the addresses of those we want to ban:

Order Allow,Deny Allow from all Deny from 127.0.0.1, 127.0.02 #Specify unwanted IPs

The method is reliable, but ineffective. Firstly, somehow it is necessary to record the requests of brute forcers and separate them from respectable visitors. Secondly, during a massive attack, you simply will not be able to track and enter the IP of hackers and bots manually. This method is only good if the administrator has a reliable “black list” of addresses.

In other cases, you can use a plugin to protect your WordPress site called WP Cerber. This solution is absolutely free, while offering a very impressive set of tools designed to prevent CMS hacking. You can install it directly from the admin panel.

By default, fairly sensible parameters are offered. However, the number of attempts should be increased to 5, in order to avoid misunderstandings.

The checkbox next to “Block IP on any wp-login.php request” should be checked if you change the admin address in the manner described earlier.

You can also use your own WP Cerber tool for these purposes:

The Citadel site protection plugin mode also does not require additional configuration. It is designed to “preserve” a project during a massive brute force attack. It is better to uncheck the box next to “Record login attempts to a file” - this will help eliminate additional load on the server.

The “Access Lists” tab is used to create a “black” and “white” list of IPs (if you have a static address, be sure to add it to the list of trusted ones), and the “Tools” section allows you to import and export previously made settings. However, these possibilities do not require separate consideration.

14. Move the configuration file

As we found out above, wp-config.php stores critical data such as login and password for accessing MySQL, as well as API keys. The next step seems obvious - protecting WordPress via htaccess by restricting file access:

< Files wp- config. php>Order allow, deny Deny from all

Order allow,deny Deny from all

However, there is a more reliable method. WordPress has a very interesting feature that few people know about. The engine allows the configuration file to be placed one level above the root directory..php can be moved to the site directory. In this case, the file will become completely unavailable via the Internet, while the information it contains will still be read by the CMS.

15. Add REFERER check

A method that has proven itself in protecting WordPress from spam will also help in resisting brute forcers. After all, brute-forcing passwords is by no means a manual task: specialized programs are used for these purposes. This means that by enabling header checking in incoming requests, you can cut out bots that “came from nowhere” with an empty HTTP REFERER:

< IfModule mod_rewrite. c>RewriteEngine On RewriteCond % (REQUEST_METHOD) POST RewriteCond % (REQUEST_URI) . (wp- comments- post | wp- login) \. php* RewriteCond % ( HTTP_REFERER) !.* tekseo. su.* [ OR] RewriteCond % ( HTTP_USER_AGENT) ^$ RewriteRule (.* ) http: //%(REMOTE_ADDR)/$1

RewriteEngine On RewriteCond %(REQUEST_METHOD) POST RewriteCond %(REQUEST_URI) .(wp-comments-post|wp-login)\.php* RewriteCond %(HTTP_REFERER) !.*site.* RewriteCond %(HTTP_USER_AGENT) ^$ RewriteRule (. *) http://%(REMOTE_ADDR)/$1

16. Secure XML-RPC

Starting from version 3.5 of WordPress, the ability to disable the XML-RPC remote procedure call protocol has disappeared. It is mainly needed to interact with mobile applications, but not everyone needs such functionality. At the same time, xmlrpc.php is actively used to carry out DDoS attacks, being the Achilles heel of the entire project.

In addition, hackers thought of using XML-RPC for brute force. Using the wp.getUsersBlogs method allows you to enumerate credentials much faster than through the admin form. Since many XML-RPC calls require authorization, a request like:

< methodCall> < methodName>wp. getUsersBlogs < params>< param>< value>< string>admin < param>< value>< string> 12345

wp.getUsersBlogs admin 12345

will cause the engine to report whether the passed combination is correct. To get rid of this scourge, you need to completely disable the protocol. You can do this in several ways:

1) By blocking access to the xmlrpc.php file via htaccess

require_once(ABSPATH . "wp-settings.php");

must be registered

function remove_x_pingback($headers) ( unset($headers["X-Pingback"]); return $headers; ) add_filter("wp_headers", "remove_x_pingback");

4) Using the Control XML-RPC publishing plugin, which returns the corresponding option to “Settings” -> “Writing”:

Please note: the add-on disables the protocol immediately after activation, and in the settings you can enable it by checking the appropriate checkbox.

17. Monitor for brute force attacks

Finally, it’s worth mentioning an interesting plugin for logging hacking attempts - Authentication and xmlrpc log writer. Although WP Cerber has built-in monitoring tools, this module will still be useful, especially for those who need the capabilities of the protocol described above. AX LogWriter can monitor brute force through xmlrpc.php, so you can assess the degree of threat and the advisability of completely refusing to use its capabilities. Finally, for those who have not been involved in the security of their project at all, a site protection plugin will open their eyes to the importance of the listed activities.

Using AX LogWriter is easy. After installation, the corresponding section will appear in the admin menu where you can make all the necessary changes:

In the “Error Type” field, select the saving method. Supports recording in the system log, Apache server log, as well as the ability to create a custom file. In the latter case, you can also configure its name (Custom Error Log Name) and directory (Custom Error Log Path). This opens up wide possibilities for the system administrator - for example, the solution can be used together with fail2ban. Also, do not forget to select the appropriate time zone in the Timezone column.

The custom log can be viewed directly from the admin panel on the Custom Log Viewer page:

Let's summarize:

The methods listed will help to significantly increase the security of your resource and protect it from brute force bots, online hooligans and practicing scriptkiddies. However, everything described above is just the tip of the iceberg. Attackers also have much more sophisticated methods in their arsenal. And in the next article we will talk about how to protect yourself from real hackers who use various vulnerabilities in the engine and server software. As in this material, in addition to the general “rules of hygiene”, key CMS settings, methods of modifying the code, as well as the most relevant plugins will be considered.


We create our own registration page for a multisite instead of the standard wp-signup.php.

In a typical WordPress installation, the registration page (login, password reset) is output by the wp-login.php file.

  • /wp-login.php - authorization
  • /wp-login.php?action=register - registration
  • /wp-login.php?action=lostpassword - password reset

There are separate conditions for a multisite in wp-login.php. So, when you follow the link /wp-login.php?action=register on a multisite, WordPress will redirect to the page /wp-signup.php. Many themes don't make the page look very attractive, so we'll make our own.

Main site of the network

By default, WordPress opens the registration page (wp-signup.php) on the main domain (site) of the network. However, you can make a separate registration page for each site in your network, even if they have different themes. We will consider the case where all sites in the network have their own registration page, but the same theme is used and the sites differ only in language. If you use different themes, you will need to write more code.

functions.php?

No. This file name seems to be mentioned in every article about WordPress. In our case, given that the registration functionality is designed for several sites, it makes sense to include it in MU plugins, which are loaded when any site is opened.

Lyrical digression

It is worth noting that MU plugins are loaded before regular plugins and before the WordPress core is fully loaded, so calling some functions can lead to fatal errors in PHP. Such “early” loading also has its advantages. For example, inside any theme you cannot attach to some actions that are triggered even before the functions.php file is loaded from the theme. An example of this is the actions from the Jetpack plugin of the form jetpack_module_loaded_related-posts (related-posts is the name of the module), with the help of which it is possible to monitor the activity of modules in Jetpack. It is impossible to “attach” to this action from the theme file, because the action has already fired before the theme is loaded - plugins are loaded before themes. You can take a look at the general picture of the WordPress loading order on the Action Reference page in the codex.

File order

MU plugins can contain any number of files and any structure that seems logical to you. I stick to something like this hierarchy:

|-mu-plugins |-|-load.php |-|-|-selena-network |-|-|-|-signup |-|-|-|-|-plugin.php |-|-|-| -|-... |-|-|-|-jetpack |-|-|-|-|-plugin.php

The load.php file contains all the necessary “plugins” for our network:

// Load Translates for all addons load_muplugin_textdomain ("selena_network", "/selena-network/languages/"); // Network Signup require WPMU_PLUGIN_DIR . "/selena-network/signup/plugin.php"; // Another plugins // require WPMU_PLUGIN_DIR ...

Inside the selena-network folder, plugin folders are stored, each with its own plugin.php, which we include in load.php. This gives you flexibility and the ability to quickly turn things off and on.

Registration page address

To specify the address of the registration page, use the wp_signup_location filter. It can be found inside the wp-login.php file and is responsible for the redirect to wp-signup.php.

Case "register" : if (is_multisite()) ( wp_redirect(apply_filters("wp_signup_location", network_site_url("wp-signup.php"))); exit;

Let's add our function to mu-plugins/selena-network/signup/plugin.php, which will return the address of the registration page on the current site:

Function selena_network_signup_page ($url) ( return home_url () . "/signup/"; ) add_filter ( "wp_signup_location", "selena_network_signup_page", 99);

selena_network is the prefix that I use in the names of all functions inside MU plugins on my site to avoid collisions, it should be replaced with your own unique prefix. The priority of adding a filter is 99, because some plugins, for example bbPress and BuddyPress, can overwrite this address with their own (MU plugins load earlier than regular plugins, see above). Note that home_url() is used instead of network_site_url() to keep the visitor on the same domain. Any URL can be used as an address.

Creating a page

Now let's create a page with the address site.com/signup/ through the normal interface, and in the child theme folder the template for our new page is page-signup.php. Instead of the word "signup" you can use a unique ID.

Inside the new template, you need to call the selena_network_signup_main() function, which will display the registration form.

It's worth noting that the whole template process is optional and you can instead create your own shortcode that will also call the selena_network_signup_main() function.

wp-signup.php and wp-activate.php

Now let's create a function that will display the registration form. To do this, copy the files wp-signup.php and wp-activate.php from the WordPress root to mu-plugings/selena-network/signup/ (and don’t forget to connect them inside mu-plugins/selena-network/signup/plugin.php) . Further manipulations with files are extremely difficult and long to describe, so you will have to do them yourself. I’ll just describe what exactly needs to be done and publish the source files of my project:

  1. At the beginning of the file, remove all require , function calls and other code outside the functions.
  2. Rename all functions by adding unique prefixes to the names.
  3. Wrap the lower part of the wp-signup.php code in the selena_network_signup_main function and at the very beginning write global $active_signup; .
  4. Replace the layout with your own in the right places.

Inside wp-activate.php you need to do approximately the same thing:

  1. Remove all code outside the functions, wrap the layout in a separate function.
  2. Change the layout in places where necessary.

The wp-activate.php file is responsible for the account activation page. As with the registration page, you need to create a separate template for it, inside of which you need to call the function from the wp-activate.php file.

Sending activation letters

The registration page sends the visitor an email with a link to activate their account. By default, this is done by the wpmu_signup_user_notification() function from the ms-functions.php file. You can borrow its functionality for your own function. The reason to avoid using this feature is that it sends the account activation link from wp-activate.php. You can “turn off” this function using the wpmu_signup_user_notification filter, returning it false (if this is not done, the activation letter will be sent twice, okay, actually two different letters).

Function armyofselenagomez_wpmu_signup_user_notification($user, $user_email, $key, $meta = array()) ( // ... // Code from function wpmu_signup_user_notification() wp_mail($user_email, wp_specialchars_decode($subject), $message, $message_headers) ; return false; ) add_filter("wpmu_signup_user_notification", "armyofselenagomez_wpmu_signup_user_notification", 10, 4);

As a result, the registration page in the Selena theme began to look much cleaner and neater.

Conclusion

There are many other not very correct ways on the Internet to do the same thing - Apache redirects, AJAX forms that will not work without Java Script, etc. I didn’t really like all this, so I tried to do it as correctly as possible on my own own website.

I note that you should edit the files carefully and try not to deviate too much from the original ones, so that in the future, if WordPress changes the wp-signup.php and wp-activate.php files, it will be easier to compare them with each other to find changes.

Don't forget to look at the source code of all the functions described above to fully understand what and how is happening inside the code.

Bonus. Protection from spammers

Even the smallest WordPress sites are often plagued by spam registrations. You can write endless conditions for filtering bots, often more like an attempt to create artificial intelligence :) In the case of a multisite, a regular redirect in Apache helped me a lot, with the help of which I asked for a 404 when opening /wp-signup.php and /wp-acitvate.php (I'm not an expert on configuring Apache, so my rules may not be very correct).

RewriteEngine On RewriteBase / RewriteRule ^wp-signup\.php - RewriteRule ^wp-activate\.php - # BEGIN WordPress # We do not touch the rules from WordPress by default :) # ... # END WordPress

P.S. I try to describe some third-party things in as much detail as possible, because when I started, sometimes there was no one to suggest and explain many things. I also believe that such small tips on other materials will encourage someone to learn something new and expand their area of ​​​​knowledge. RewriteRule entries use regular expressions, they are not complicated at all, for example, the ^ character means the beginning of a line.

Let's think about who a hacker is? A hacker is not a cracker! People often confuse these concepts. A hacker is, first of all, a person with unconventional thinking, and this is his strength, so to speak.

To successfully resist a hacker, you also need to learn to think outside the box. As they say, we knock out wedges with wedges.

Today I will offer you a very unusual way to protect yourself from php include attacks. Of course, it is not suitable for everyone. And to be honest, it protects not from the attack itself, but from its detection. Intrigued?

How to find inclusion...

Let's first understand how exactly an attacker tries to detect a vulnerability.

It looks like this. The attacker modifies all incoming parameters one by one, assuming that the data from these parameters ends up in the include function. Well, or if it’s simply trying to “include” files. And in order to determine whether there is a vulnerability or not, he needs to include some file on the target system (he got it - there is a vulnerability, no - there is no vulnerability).

Naturally, if an attacker acts from the outside, then he does not know the structure of directories and files, and cannot include any file, since he will not know the path to it. But there are files that always exist in the system, and to which you always have read rights. For Linux, this is /etc/passwd, and for Windows, let it be C:\boot.ini. But by the way, we are of little interest to Windows, so we will continue to talk about passwd

/etc/passwd

You've probably come across more entries like this in your logs:

Action=../etc/passwd%00
?action=../../etc/passwd%00
?action=../../../etc/passwd%00
?action=../../../../etc/passwd%00
?action=../../../../../etc/passwd%00
?do=../etc/passwd%00
?do=../../etc/passwd%00
?do=../../../etc/passwd%00
?do=../../../../etc/passwd%00
?do=../../../../../etc/passwd%00
?id=../etc/passwd%00
?id=../../etc/passwd%00
?id=../../../etc/passwd%00
?id=../../../../etc/passwd%00
?id=../../../../../etc/passwd%00

If yes, then know that they tried to find php include (or the ability to read arbitrary files, but we are not interested in that now). So, if one of your parameters is not processed properly and ends up in a function include(), then the /etc/passwd file would be included, its contents would be interpreted as a PHP script, and since it does not contain PHP code tags, it would be output to the browser unchanged. This would serve as a “marker” for the attacker of the presence of a vulnerability.

Why am I writing this, because when searching for includes, an attacker will definitely (I guarantee that in 90% of cases) try to include a file /etc/passwd.

Defend yourself, sir!

You’re probably thinking now: “Does he want to offer a regular WAF and filter packets based on the presence of /etc/passwd in them?” No. This is the standard way. This is an example of how an ordinary person thinks.

Let's show a little imagination. Why don't we just add some PHP code to the contents of the passwd file? And if suddenly an attacker manages to include it, then our PHP code will be executed. (Do you think it’s nonsense? - look at the conclusion)

Since we know that the only one who would think of including this file is a hacker, our php code should ban it, and in order to prevent our system from being hacked further, block the vulnerable file, and it is advisable to notify the administrator about the incident.

But how can you add php code to /etc/passwd since its syntax is strictly regulated? Each user has a “comment” field - a description of the user, you can enter anything you want there (except for the colon, of course). Therefore, we take and add the user to the system with the comment we need. After this /etc/passwd will contain this line

root:x:0:0:Superuser:/:
daemon:*:1:5::/:/sbin/sh
bin:*:2:2::/usr/bin:/sbin/sh
sys:*:3:3::/:
adm:*:4:4::/var/adm:/sbin/sh
securityuser:*:1001:1001::/:

Well, in the connected script we already perform the actions you need - ban the user, block the request, notify the administrator.

As a result, we have come up with a kind of trap that can protect your site from hacking.

Conclusion

Yes, I am fully aware that everything written above looks like nonsense. And I understand perfectly well that no one will use this in practice. But that's not why I wrote. I wrote to show an example of a non-standard approach in the field of protection.

Thanks for your attention =)

When it comes to application security, it is important to take care not only of the hardware and operating system, but also of writing secure scripts. In this article, you will learn how to ensure the security of your application and make it less vulnerable. Below is a list of measures that will help you protect your application from all kinds of attacks:

  1. Validation of incoming data
  2. Protection against XSS attacks
  3. Protection against CSRF attacks
  4. Preventing SQL injections
  5. File system protection
  6. Session data protection
  7. Error Handling
  8. Protecting included files

Validation of incoming data

When designing an application, you should strive to protect it from “bad” incoming data. The rule to follow is something like this: “Never trust what the user enters.” While most users are not a threat, there is always the possibility that someone might want to hack your site using bad data entered through forms or the address bar. If you always check and filter incoming data, then you have a good chance of writing a secure application.

Always check your data in PHP scripts. If you use JavaScript to validate data, an attacker can disable it in their browser at any time. In this case, your application is in danger. Nobody is against JavaScript validation, but for good protection you need to double-check the data in PHP scripts.

Protection against XSS attacks

Cross-site scripting or XSS attack is an attack based on code injection on potentially vulnerable pages. The danger is that malicious code can be entered through forms and then displayed in the browser.

Let's say your site has a form for entering comments, which are immediately displayed after adding. An attacker can enter a comment containing JavaScript code. After submitting the form, the data is sent to the server and entered into the database. After this, the data is retrieved from the database and the new comment is displayed on the HTML page, including the embedded JavaScript code. It can redirect the user to some malicious page or to a phishing site.

To protect your applications, pass incoming data through the strip_tags() function, which will remove all tags present. When displaying data in a browser, use the htmlentities() function.

Protection against CSRF attacks

The next type of attack we'll look at is the CSRF attack, or cross-site request forgery. The attacker uses various tricks to obtain confidential information or complete a transaction without the knowledge of the victim. This mainly happens on poorly protected sites, where business logic is based on GET requests.

Generally speaking, GET requests are idempotent. Idempotency, in this context, means that the same page can be accessed as many times as desired without any third-party intervention. That is why GET requests should only be used to gain access to information, but in no case to carry out various types of transactions.

The following simple example shows how an unprotected website can be subject to a CSRF attack:

Let's assume that Bob wants to perform a CSRF attack on Alice. He generated a special url address and sent it to Alice by e-mail:

Visit my site!

If Alice is authorized on example.com and follows this link, then $1000 will be transferred from her account to Bob’s account. Alternatively, Bob can send the image as well, and add a “bad” address in the src attribute.

The browser will not be able to display this image, since it does not exist, but the request will be made without Alice's knowledge and participation.

To prevent this type of attack, use only POST requests to processes designed to change information in the database. Don't use $_REQUEST. Use $_GET to process GET parameters, and $_POST to retrieve POST parameters.

As an additional measure, you can generate some kind of unique token and attach it to each POST request. When a user logs into the system, a random token can be generated and recorded in the session. Since all forms are displayed to the user, this token must be written to a hidden field. The business logic of the application must provide functionality that will check the token from the forms and the token stored in the session.

Preventing SQL injections

You should use PDO to run database queries. With parameterized queries and prepared expressions, you can mitigate the threat of SQL injections.

Let's look at the following example:

In the code above, we send a request to the prepare() method, including the named parameters: :name and:age . Thus, the query is pre-compiled for further data substitution. When calling the execute() method, the request is completely generated and executed. If you use a similar technique, then all attempts by an attacker to carry out SQL injection will be reduced to zero.

File system protection

As a responsible developer, you should always write code that doesn't put your file system at risk. Let's look at the code that downloads a file depending on the data submitted by the user.

This script is very dangerous, because it allows you to gain access to any directory that is accessible from the script file: the directory with sessions, system folders, and much more.

Session data protection

By default, all session information is written to the temp directory. If you use shared hosting, someone besides you can write a script and read session data. Therefore, beware of storing passwords or credit card numbers in sessions.

If you still need to store such data in a session, then encryption would be the best measure. This does not completely solve the problem, since the encrypted data is not 100% secure, but the stored information will be unreadable. You may also want to consider storing session data in another location, such as a database. PHP has a special method session_set_save_handler() that will allow you to store session data in your own way.

Since PHP 5.4 you can pass an object of type SessionHandlerInterface to session_set_save_handler() .

Error Handling

During application development, it is worth paying attention to all types of errors that may arise, however, they must be hidden from end users. If errors are displayed to users, then this makes your site vulnerable. So the best solution would be to have a different configuration for the production server and the development server.

On a public server, you need to disable options such as display_errors and display_start_up_errors, but options such as error_reporting and log_errors must be active so that all errors encountered by users are recorded in the logs.

You can also use set_error_handler to define your own error handler. However, there may be limitations here, because the native handler is inferior to the native PHP mechanism. Errors E_CORE_ERROR , E_STRICT or E_COMPILER_ERROR will not be caught in the same file as the specified handler. Moreover, errors that may occur in the handler itself also cannot be caught.

For a more elegant way of catching exceptions, potentially dangerous code should be placed in a try/catch block. All native exceptions must be objects of Exception classes or subclasses. If exceptions were thrown, they can be processed in a try/catch block.

Protecting included files

Often in PHP scripts other files are loaded, such as connecting to the database and many others. Some developers give such files the extension .inc. PHP does not parse such files by default. If you access them directly, the user will be able to see the text of this file. If a hacker manages to gain access to the file storing the connection data to the database, then he can subsequently gain access to all the data of your application. So always use the .php extension for uploaded files and store them where there is no direct user access.

Bottom line

If you follow these 8 rules, this will greatly improve the resistance of your application to various types of attacks. Don't trust data entered by users, protect your files and database.