CS.XSS.PERSIST

Cross-site scripting persisting vulnerability

The CS.XSS.PERSIST checker flags instances of code where input is provided by data directly from the HTTP request and that data is stored in a database, message forum, visitor log, or other trusted data store that can be read back at the later time.

Vulnerability and risk

A Cross-site scripting (XSS) attack is a type of attack in which software does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.

XSS vulnerabilities occur when:

  1. Untrusted data enters a web application, typically from a web request.
  2. The web application dynamically generates a web page that contains this untrusted data.
  3. During page generation, the application does not prevent the data from containing content that is executable by a web browser, such as JavaScript, HTML tags, HTML attributes, mouse events, Flash, ActiveX, etc.
  4. By using a web browser, a victim visits the generated web page that contains the malicious script that was injected using the untrusted data.
  5. Because the script comes from a web page that was sent by the web server, the victim's web browser executes the malicious script in the context of the web server's domain.
  6. This effectively violates the intention of the web browser's same-origin policy, which states that scripts in one domain should not be able to access resources or run code in a different domain.

There are three main kinds of XSS:

  • Type 1: Reflected XSS (or non-persistent)
  • Type 2: Stored XSS (or persistent)
  • Type 0: DOM-Based XSS

The application stores dangerous data in a database, message forum, visitor log, or other trusted data store. At a later time, the dangerous data is subsequently read back into the application and included in dynamic content. From an attacker's perspective, the optimal place to inject malicious content is in an area that is displayed to either many users or particularly interesting users. Interesting users typically have elevated privileges in the application or interact with sensitive data that is valuable to the attacker. If one of these users executes malicious content, the attacker may be able to perform privileged operations on behalf of the user or gain access to sensitive data belonging to the user. For example, the attacker might inject XSS into a log message, which might not be handled properly when an administrator views the logs.

Mitigation and prevention

To prevent XSS attacks, neutralize all user-controllable input before placing that data in output that is used as a web page.

Vulnerable code example

Copy
  protected void Submit_Click(object sender, EventArgs e)
  {
      try
      {
          var txt = MyTextbox.Text;
          saveValueInDataBase( txt );             // CS.XSS.PERSIST
      }
      catch (Exception) { }
  }
   
 void saveValueInDataBase(string val)
 {
     SqlConnection con = new SqlConnection();
     SqlCommand cmd = new SqlCommand("sp_insert1", con);
   
     cmd.CommandType = CommandType.StoredProcedure;
     SqlParameter outpara = new SqlParameter("@id", SqlDbType.Int);
     outpara.ParameterName = "@id";
     outpara.SqlDbType = SqlDbType.Int;
     outpara.Direction = ParameterDirection.Output;
     cmd.Parameters.Add(outpara);
     cmd.Parameters.AddWithValue("@value", val);   
     con.Open();
     cmd.ExecuteNonQuery();
     con.Close();
 }

In this examaple, Klocwork reports a defect on line 6, indicating, "Unvalidated XSS string 'txt' is received from 'get_Text()' at line 5. This is being saved through call to 'saveValueInDataBase()' at line 6. This allows for a cross-site scripting vulnerability."

Fixed code example

Copy
  protected void Submit_Click(object sender, EventArgs e)
  {
      try
      {
          var txt = MyTextbox.Text;
          saveValueInDataBase(Server.HtmlEncode( txt ));      // no defect
      }
      catch (Exception) { }
  }
   
 void saveValueInDataBase(string val)
 {
     SqlConnection con = new SqlConnection();
     SqlCommand cmd = new SqlCommand("sp_insert1", con);
   
     cmd.CommandType = CommandType.StoredProcedure;
     SqlParameter outpara = new SqlParameter("@id", SqlDbType.Int);
     outpara.ParameterName = "@id";
     outpara.SqlDbType = SqlDbType.Int;
     outpara.Direction = ParameterDirection.Output;
     cmd.Parameters.Add(outpara);
     cmd.Parameters.AddWithValue("@value", val);     
     con.Open();
     cmd.ExecuteNonQuery();
     con.Close();
 }

In this fixed example, Klocwork doesn't report a defect.

Related checkers

Security training

Application security training materials provided by Secure Code Warrior.