Professional Documents
Culture Documents
Security Notes
Security Notes
Vulnerable code
Remediation
Secure code
Cross-Site Scripting (XSS) attacks are a type of injection, in which malicious scripts are injected into otherwise
benign and trusted web sites. XSS attacks occur when an attacker uses a web application to send malicious
code, generally in the form of a browser side script, to a different end user.
Cross Site Scripting, or XSS comes in three major flavors: Reflected, Stored, and DOM-based. This document
will discuss the first two. It is a vulnerability that arises when a developer chooses to trust user input without
validation.
Reflected XSS
Reflected XSS is very common in web applications. These attacks occur when a client machine sends a
script to a webserver that reflects it back to the client, which executes the script.
Stored XSS
Similar to the Reflected Version, Stored XSS occurs when an attacker can send a script to a web server
that stores the script on the server side, and may serve it back to clients whenever they interact with it.
</pega:otherwise>
</pega:choose>
<%
if(toolTip.startsWith(".")){
toolTip = tools.getActive().getParentPage().getString(toolTip);
strValue = tools.getLocalizedTextForString("pyCaption",toolTip);
%> title='<%=strValue%>'<%
%>
>
<%
strValue = tools.getLocalizedTextForString(tools.getParamValue("FiledValueKey").length() == 0 ?
"pyCaption" : tools.getParamValue("FiledValueKey"),tools.getActiveValue());
%>
<%=strValue%>
</a>
All values that come from a client that are not validated or filtered on input, including Parameters and
Clipboard Properties (Active Values) must be encoded during output processing.
There are several APIs to use for encoding, depending upon the context of the output data (HTML, URL,
RichText, etc)
tools.appendCSF()
StringUtils.crossScriptingFilter()
StringUtils.filterRichText()
StringUtils.URLCrossScriptingFilter()
StringUtils.reversibleCrossScriptingFilter()
escapeCrossScriptingFilter()
escapeIntoJSON()
</pega:otherwise>
</pega:choose>
<%
if(toolTip.startsWith(".")){
toolTip = tools.getActive().getParentPage().getString(toolTip);
strValue = tools.getLocalizedTextForString("pyCaption",toolTip);
strValue = StringUtils.crossScriptingFilter(strValue);
%> title='<%=strValue%>'<%
%>
>
<%
<%=strValue%>
</a>
Cross Site Scripting (XSS)
Description
Vulnerable code
Remediation
Secure code
A SQLi vulnerability allows a user to send SQL commands to a server and have the underlying database execute
them. This means a user could send DBMS (Database Management System) commands to disconnect the
database, or change passwords. The user could access data from the database that he/she is not authorized to
see, or even change information he/she should not be allowed to change. There are two main flavors of SQLi
though their modelling and remediation are exactly the same:
3. PreparedStatement (CoreEngine)
In the engine, it may become necessary to write a SQL query. In this case utilize prepared statements like so:
String selectTableSQL = "select * from myTable where myColumn = ?";
DatabaseConnection connection =
getThreadConnectionStore().getConnection(instanceClassGroup.getDatabase());
DatabasePreparedStatement stmt = connection.prepareStatement(selectTableSQL, instanceClassGroupName,
DatabasePreparedStatementImpl.sSQLSelect, sLookupTable);
stmt.setString(1, "myColumnName");
DatabaseResultSet results = (DatabaseResultSet) stmt.executeQuery();
Vulnerable code
Remediation
Secure code
1. Denial Of Service
This XML snippet would print out "lol" one billion times (Wiki Billion Laughs)
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ELEMENT lolz (#PCDATA)>
<!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>
This would take up approximately 3 GB, since "lol" is 3 bytes * 1,000,000,000 ~= 2.79 GB. Longer strings would
take more memory.
2. Additionally one could chain the file inclusion vector with this attack vector, so that a file's contents is
printed one billion times, which would use system I/O time, as well as have huge memory consumption.
<?xml version="1.0"?>
<!DOCTYPE file [
<!ELEMENT file ANY>
<!ELEMENT shad SYSTEM "file:///etc/shadow">
]>
<XXEDemo>
<output>
<file>&shad;</file>
</output>
</XXEDemo>
Vulnerable code
Remediation
Secure code
We often do our own deserialization using the capabilities provided by the Java API. Since
serialization/deserialization vulnerabilities are common and some known instances like the Commons-
Collection deserialization have allowed arbitrary code execution, we should be vigilant when performing
deserialization to make sure that we do not have vulnerabilities in our functionality.
{
public static void main(String[] args)
{
try
{
StudentInfo si = new StudentInfo("Abhi", 104, "110044");
FileOutputStream fos = new FileOutputStream("student.ser");
Objectoutputstream oos = new ObjectOutputStream(fos);
oos.writeObject(si);
oos.close();
fos.close();
}
catch (Exception e)
{ e. printStackTrace(); }
}
}
/////////////////////////////////////////////////////////
class DeserializationTest
{
public static void main(String[] args)
{
StudentInfo si=null ;
try
{
FileInputStream fis = new FileInputStream("student.ser");
ObjectOutputStream ois = new ObjectOutputStream(fis);
si = (StudentInfo)ois.readObject();
}
catch (Exception e)
{ e.printStackTrace(); }
System.out.println(si.name);
System.out. println(si.rid);
System.out.println(si.contact);
}
}
If possible, do not deserialize untrusted data without validating the contents of the object stream. In order to
validate classes being deserialized, the look-ahead deserialization pattern should be used.
The object stream will first contain the class description metadata and then the serialized bytes of their
member fields. The Java serialization process allows developers to read the class description and decide
whether to proceed with the deserialization of the object or abort it. In order to do so, it is necessary to
subclass java.io.ObjectInputStream and provide a custom implementation of
theresolveClass(ObjectStreamClass desc) method where class validation and verification should take place.
While the ideal approach in this situation is to whitelist the expected classes, in some scenarios, this approach
may not be practical. A blacklist approach is better for complex object graph structures. Keep in mind that
although some classes to achieve code execution are publicly known, there may be others that are unknown or
undisclosed, so a whitelist approach will always be the preferred approach. To avoid denial of service attacks, it
is recommended that you override the resolveObject(Object obj) method in order to count how many objects
are being deserialized and abort the deserialization when a threshold is surpassed.
public class LookAheadDeserializer {
Vulnerable code
Remediation
Secure code
A common technique in Pega 7 applications is to use conditional visibility and/or privileges on user interface
elements like menu options or sections. This technique is an effective way to have the user interface display
what the user needs to see without displaying what the user does not need to see. In some situations, this
technique accomplishes a part of what is intended but is thought to accomplish all of what is intended. For
example, if there is a menu option that you want admin users to be able to execute, but you do not want
regular users to be able to execute, you can hide the option.
While hiding unusable menu options is important, by itself it does not prevent the functionality underlying the
menu option from being used. In order to prevent the functionality from being used you also have secure the
underlying functionality.
An easy way to replicate an attack for proof of concept or testing purposes is to get a copy of the URL used by
an authorized user and change the parameters in the URL to match that of an unauthorized user and run the
URL from the unauthorized user's session. For example, the 'manger tools' option in the PegaCS application is
run by the admin user with the following URL:
http://10.61.8.217:9080/prweb/g39KfsPA6--ty8Xd36mkqQ%5B%5B*/!TABTHREAD0?pyActivity=
%40baseclass.pzTransformAndRun&pzFromFrame=&pzPrimaryPageName=pyDisplayHarness&pzTransactionId
=&preActivity=&preActivityParams=&action=display&harnessName=CPMManagerToolsHarness&className=C
PM-
Portal&pyDataTransform=&pyPreActivity=doUIAction&pzPrimaryPage=pyDisplayHarness&checkForNewPage=t
rue&portalName=CPMInteractionPortal&contentID=_blank&label=&api=setDocumentLabel&readOnlyMode=f
alse&pzHarnessID=HID3D38FC1816C4F9487696A5FBCF6D38D8
If I look at a URL from an unauthorized user and extract the access group hash (IdC5PtOBqG4%5B*) and
pzHarnessID (HID27A5F3C1B0EEC808332998F6D7EC1B1F)
http://10.61.8.217:9080/prweb/IdC5PtOBqG4%5B*/!TABTHREAD0?
pyActivity=pzRunActionWrapper&pzTransactionId=&pzFromFrame=&pzPrimaryPageName=pyDisplayHarness&
pzDataTransform=CPMSetCurrentLeftNavSelected&inStandardsMode=true&AJAXTrackID=1&pzHarnessID=HID
27A5F3C1B0EEC808332998F6D7EC1B1F&HeaderButtonSectionName=SubSectionCPMDashboard_ChartsBB
and replace the existing the access group hash and pzHarnessID in the first URL with them I get the following:
http://10.61.8.217:9080/prweb/IdC5PtOBqG4%5B*/!TABTHREAD0?pyActivity=
%40baseclass.pzTransformAndRun&pzFromFrame=&pzPrimaryPageName=pyDisplayHarness&pzTr
ansactionId=&preActivity=&preActivityParams=&action=display&harnessName=CPMManagerTools
Harness&className=CPM-
Portal&pyDataTransform=&pyPreActivity=doUIAction&pzPrimaryPage=pyDisplayHarness&checkFo
rNewPage=true&portalName=CPMInteractionPortal&contentID=_blank&label=&api=setDocumentL
abel&readOnlyMode=false&pzHarnessID=HID27A5F3C1B0EEC808332998F6D7EC1B1F
and if I run this URL in the unauthenticated user's session I get the manager tools with the same level of
functionality as the admin user.
The best way to remediate the attack depends on the situation but it is a best practice to have actions that
require authorization check for authorization before every potential execution. There are 3 ways to
accomplish this:
1. Privilege : One way to incorporate checking for authorization before the execution of a rule is to use the
Security Tab of rules to only allow authorized users to invoke those rules. One example of this from Pega 7 is
the Approve Flow Action in @baseclass which can only be invoked by a user that has either the ActionApprove
or the AllFlowsActions privilege for @baseclass.
2. R-U-F : Another way to check for authorization before execution is using built-in functions that check
privileges and/or roles like HaveAuthorization, HavePrivilege, or HaveRole. An example of this can be found in
the pzModifyAllowed Access When rule.
3. Access When : Another way to check for authorization before execution is by using Access When rules.
Access When rules are similar to When rules from the UI perspective, however Access When rules are specific
to checking whether a user should be allowed to perform an operation or to access specific information
Vulnerable code
Remediation
Secure code
What is a secure ID? A secure ID is used as a key that hides important data that you don't want a user knowing
about. This data could include Pega internal information, such as requestor information, or the data could be
personal information of our customers' clients. Generating these IDs in as secure a manner as possible is highly
important, given the data they should hide. This document will detail the ways to generate an ID securely and
also talk about how to rearchitect your solutions to ensure that your IDs betray no data.
Random r=new Random();
int i=r.nextInt();
In its simplest form, IDs should be generated using PRRandom. PRRandom uses java.security.SecureRandom
and reseeds the data frequently, further hampering attackers.
IDs should be used as keys to hide important data stored server-side. That data should never be sent in any
format to the client.
The only place System Time should be considered is to use it as a timestamp, not for any secure IDs.