 Hey there, and welcome to Learn WordPress. In this tutorial, you're going to learn how to protect your WordPress plugins and themes against common security vulnerabilities. You will learn about common vulnerabilities to consider when building a WordPress plugin or theme, examples of how to prevent each type of vulnerability, and where to find more information around developing plugins and themes securely. Security is an ever-changing landscape, and vulnerabilities evolve over time. You just have to take a look at the Open Web Application Security Project Top 10 list to see how things have changed from 2017 to 2021. The benefit of using WordPress as the base of your next development project is that many of these vulnerabilities have already been addressed by the WordPress core team. However, if you're building a custom theme or plugin that's going to process any user data, you will need to ensure that your code does not create any of the common security vulnerabilities discussed in this lesson. In the introduction to Security Developing Plugins tutorial, we looked at the five main security principles that you should follow when developing a custom plugin or theme. You should secure or sanitize your inputs. You should validate all data. You should secure or escape your outputs. You should make sure you prevent untrusted requests. And you should always check user capabilities. To see how to apply these five principles and prevent common vulnerabilities, let's look at the code of the badly coded form submission plugin and fix any security vulnerabilities we find. At the top of the main plugin file, some constants are set up, which are used elsewhere in the plugin. The first two are used to define page slugs that the plugin will use to redirect to. For this plugin functionality to work, these pages need to exist with the correct slugs. Next, a callback function is registered on the plugin activation hook. This sets up a custom form submissions table in the database. After that, the plugin's admin JavaScript and front-end style CSS files are in queue. Next, a shortcode is registered, which is used to display a form on the front-end. After that, a callback function is hooked into the WP action, which is what the plugin uses to process the form submission. Next, the plugin registers an admin submenu, which displays a list of form submissions. Next, there is a function which renders the admin page when clicking on the submenu link. Then, there is a function that the admin submenu uses to fetch the form submissions from the database. Lastly, there is a callback function that's hooked into a WP Ajax hook, which is the Ajax endpoint that the plugin uses to delete form submissions from the admin submenu page. The admin JavaScript file handles the Ajax request to delete form submissions from the submissions page. The front-end style CSS file is used when the user enters a class attribute for the shortcode. It defaults to red, but the user can change this to blue. It simply adds a border to the form. When the shortcode is added to a post or page, it renders the form and users can submit their details. When the form is submitted, it will redirect either to the success or error page, depending on whether the form submission was successful or not. Then, in the dashboard, admins can view those form submissions and delete them. First common vulnerability we're going to look for is SQL injection. SQL injection happens when values being inputted are not properly sanitized, allowing for any SQL commands using the inputted data to potentially be executed on the database. First place we need to tackle a possible SQL injection vulnerability is in the function that processes the form data. We need to make sure that any post data is sanitized before being used in the query. We also need to either use the WPDB prepare or insert functions instead of just the query function. This will ensure that the name and email field values are both sanitized as they are accepted from the form submission request and that they are sanitized before being used to store the record in the database. While this might seem like overkill, if you just sanitize the inputs and the code is later changed to use the values in a different way, you could still be vulnerable to a SQL injection. The other place we need to prevent SQL injection is in the function that deletes the form submission. Again, we need to make sure that any post data is sanitized before used in the query. And we either need to use the WPDB prepare or delete functions. Because the ID of the form submission is an integer, we can use the PHP typecasting functionality to make sure it's always cast as an integer. The next common vulnerability we're going to look for is cross-site scripting. Cross-site scripting happens when a nefarious party injects JavaScript into a web page, which can be used to launch multiple different attacks or malicious activities from the website. You can avoid cross-site scripting vulnerabilities by escaping your outputs, stripping out any unwanted data. Your code should escape dynamic content with the proper function depending on the type of content being escaped. Let's look at some places where data is being output and make sure that it's being escaped properly. The first place is in the rapid div of the form shortcode callback. Here, the class attribute of the div is rendered based on the attributes passed to the shortcode. This is a potential cross-site scripting vulnerability as the class attribute is not escaped. Note that you should specifically use the ESC underscore ATTR function to escape HTML attributes. Next, we have the function which renders the admin page. Here, the submission name, submission email and submission ID should be escaped. In this example, you can use ESC underscore HTML, because this is the correct function to use anytime an HTML object encloses a section of data being displayed. Always pay close attention to what each escaping function does, as some will remove HTML while others will permit it. You must use the most appropriate function to the content and context of what you're echoing. Finally, you cast the ID to an integer again, as that is being used in a data attribute. You could also use the ESC attribute function we used earlier, but in this case, casting it to an integer is perfectly fine. The next vulnerability to prevent is cross-site request forgery. Cross-site request forgery has been a nefarious party trickster user into performing an unwanted action within a web application that they are authenticated in. When developing with WordPress, becoming familiar with WordPress nonces is a must to help prevent cross-site request forgery. A nonce is a number used once and provides a way to verify that the origin of the request is legitimate. You create a nonce when you need to verify that the request is legitimate. You output or pass the nonce to wherever needs to make the request, and finally you verify the nonce when the request is made. There are two possible cross-site request forgery vulnerabilities in this plugin. The first is when the form is submitted and the data is processed. To fix this, we need to add a nonce to the form being rendered in the shortcode and then verify it when the form is submitted. In the form, we use the wp nonce field function to add a hidden field with the nonce. Notice how you pass in an action and a name to this function. The action is used to identify the nonce and the name is the name of the field that will be added to the form. If you inspect the form, you can see the nonce field, which is using the name you passed to the function and the nonce value. Then in the form submission function, you can verify the nonce using the wp verify nonce function, passing in the value of the nonce field and the action. It's usually a good idea to also check that the nonce field has been passed in the request and then verify that the nonce is valid. A better way to do this code would be to check if the nonce field doesn't exist or if the nonce field is not verified and then redirect to the error page. Here, we are checking that the nonce field has been passed in the request and then verifying that the nonce is valid. If the nonce is not passed or is invalid, we redirect to the error page. The other place you need to prevent CSRF is in the Ajax callback used to delete the form submission. To fix this, first you need to manually create a nonce using wp create nonce and then pass this nonce to the JavaScript layer using wp localize script. Notice how you pass the nonce as a property of the wp learn Ajax object, which also contains the Ajax URL. This is what is used in the jQuery post request to make the request happen. Then we need to include the nonce in the jQuery post request. Notice how you specify the nonce in the data passed to the post request as underscore Ajax underscore nonce. This is the name that WordPress expects when processing an Ajax request. Lastly, in the Ajax callback function, verify the nonce using the handy check Ajax referrer function. Notice that the string passed to check Ajax referrer is the same string passed to wp create nonce when creating the nonce. If the check Ajax referrer function fails, it will cause execution to stop. So you don't need to check the result of this function. There's one more vulnerability in this plugin, and it's a broken access control vulnerability. Broken access control is when a user is able to access a resource they should not be able to access. For example, a user might be able to access an admin function, even though they are not an administrator. In this example, you have a broken access control vulnerability in the Ajax callback function. At the present moment, any authenticated user could make a request to this Ajax request URL with the right data, and it would delete a form submission. To fix this, you can use the WordPress roles and capabilities API to check that the user has the correct permissions to delete a form submission. In this case, it could be just as simple as checking that the user is an admin user. Here, you're using the current user can function to check whether the user has the manage options permission, which is specifically an administrator permission. If this check fails, it will simply return an authentication error result. Note that we're doing two checks here, one against cross-site request forgery and one for access control. In this example, the order of execution is not super important, but in general, it's a good idea to check for cross-site request forgery first and then check for access control. There's one additional security vulnerability in this plugin. It's a tough one to spot, but all instances of WP redirect should be replaced with WP safe redirect. This is because the code is redirecting to a local URL, and WP safe redirect checks whether the location it's using isn't a loud host, if it has an absolute path. This prevents the possibility of malicious redirects if the redirect location is ever attacked. To learn more about common web application vulnerabilities, make sure to visit the Open Worldwide Application Security Project or OWASP's top 10 list. Then make sure to read the entry in the WordPress developer documentation on security, as it includes code examples, additional information on security-based practices, and much more. Happy coding!