FogBugz Plugin API > Plugin Security
This article will demonstrate how functions exposed by CSecurityApi and a set of best practices can help protect your plugin (and your FogBugz site) from cross-site scripting attacks, SQL injection attacks, and cross-site request forgery attacks.
Cross-Site Scripting Attacks
Prevent XSS attacks by using HTMLEncode
The .NET framework's System.Web.HttpUtility class includes an HTMLEncode method that converts potentially dangerous symbols (including HTML brackets, semicolons, etc.) into their harmless "escaped" HTML equivalent.
When embedding a string in HTML content, it's best practice to encode the string if it could have been entered or affected by an external user. For example, the following block of code uses HTMLEncode to "sanitize" data regarding a "kiwi" record that was entered into the database:
Note that HtmlEncode and HtmlAttributeEncode do not escape single quotes ('). Because of this, html that is constructed using single-quoted attributes isn't secure against XSS unless additional escaping steps are taken. To solve this, we strongly recommend using double-quoted html attributes in conjunction with HtmlEncode- e.g.:
"<div title=\"" + HttpUtility.HtmlEncode(sTitle) + "\">" //(safe)
"<div title='" + HttpUtility.HtmlEncode(sTitle) + "'>" //(Not secure)
SQL Injection Attacks
SQL injection attacks insert malicious SQL commands into database queries. Applications are vulnerable to such attacks if they assemble database queries by concatonating a series of variables (set by an external user) and SQL clauses.
Prevent SQL injection attacks by using named parameters
The article Generic Database Access introduced the set of database query classes exposed to FogBugz plugins. The CUpdateQuery, CDeleteQuery, CSelectQuery, CInsertQuery, and CInsertSelectQuery classes allow developers to build platform-agnostic queries, one clause at a time.
They also allow developers to introduce named parameters into their queries, which can safely be assigned the value of a variable set by an external user. This is because the SQL interpreter treats them as substituted values rather than semantically meaningful portions of the query.
The following example uses CSelectQuery to get all the cases assigned to a particular user, as well as perform a join with the "Person" table in order to get data regarding the user. Note that the "ixPerson" value passed in by the request object (and presumably set by an external user) is assigned to a named parameter rather than tacked on the SQL Query directly:
Cross-Site Forgery Attacks
Cross-Site Request Forgery (CSRF) Attacks exploit the trust a website has established with a user's web browser by transmitting to the website unathorized, malicious commands from that browser. CSRF attacks often operate by serving content to the user's browser that references the URL of the target website and appends malicious commands to the querystring of that URL.
Prevent CSRF attacks by using FogBugz action tokens
The CSecurityApi class exposes two methods designed to effectively combat CSRF attacks, GetActionToken() and ValidateActionToken().
A FogBugz "Action Token" is a globally unique identifier automatically created and stored by FogBugz when the method GetActionToken() is called. The action token returned by GetActionToken() is normally embedded in a hidden input field by server-side ASP.NET code.
Using Action Tokens with Forms
When the user submits a plugin-created form, this token should be posted back to the server, where it is then validated using ValidateActionToken(). This function compares the passed action token against the set of valid tokens currently active on the FogBugz site. Even though action tokens will remain active for a whole week, developers are encouraged to generate a new action token each time a secure page is served.
Note that GetActionToken() and ValidateActionToken() take either 1 or 2 arguments because action tokens can optionally be assigned a name. If a call to GetActionToken() assigns a name to a token, then the name / token pair must be passed to ValidateActionToken() in order for validation to be successful.
The following example form allows users to add a new kiwi to a database of kiwis. Notice that it contains a hidden field containing the action token. For an example plugin which uses action tokens, see Tutorial- A Simple Todo List.
When the form is submitted, we just have to make sure that the action token is valid before actually inserting the new kiwi into the database:
Using Action Tokens with AJAX requests
Using action tokens to verify the authenticity of an AJAX request is very similar. Rather than including the token in a form, the developer need only include it as an additional querystring parameter sent along with the AJAX request: