Use HTTPS for Wikimedia query-help links - #22410
Conversation
geoffw0
left a comment
There was a problem hiding this comment.
LGTM.
(I checked a handful of the new URLs manually, and had Copilot look for unusual cases)
|
|
||
| <!-- | ||
| <p>Wikipedia article on the <a href="http://en.wikipedia.org/wiki/Double-checked_locking">Double-Checked Locking Pattern</a></p> | ||
| <p>Wikipedia article on the <a href="https://en.wikipedia.org/wiki/Double-checked_locking">Double-Checked Locking Pattern</a></p> |
There was a problem hiding this comment.
This change is in a comment, but it's not doing any harm to update it along with the others.
|
QHelp previews: cpp/ql/src/Best Practices/Exceptions/CatchingByValue.qhelpCatching by valueCatching an exception by value will create a new local variable which is a copy of the originally thrown object. Creating the copy is slightly wasteful, but not catastrophic. More worrisome is the fact that if the type being caught is a strict supertype of the originally thrown type, then the copy might not contain as much information as the original exception. RecommendationThe parameter to the Examplevoid bad() {
try {
/* ... */
}
catch(std::exception a_copy_of_the_thrown_exception) {
// Do something with a_copy_of_the_thrown_exception
}
}
void good() {
try {
/* ... */
}
catch(const std::exception& the_thrown_exception) {
// Do something with the_thrown_exception
}
}
References
cpp/ql/src/Best Practices/Exceptions/ThrowingPointers.qhelpThrowing pointersAs C++ is not a garbage collected language, exceptions should not be dynamically allocated. Dynamically allocating an exception puts an onus on every As a special case, it is permissible to throw anything derived from Microsoft MFC's RecommendationThe Examplevoid bad() {
throw new std::exception("This is how not to throw an exception");
}
void good() {
throw std::exception("This is how to throw an exception");
}
References
cpp/ql/src/Best Practices/Likely Errors/OffsetUseBeforeRangeCheck.qhelpArray offset used before range checkThe program contains an and-expression where the array access is defined before the range check. Consequently the array is accessed without any bounds checking. The range check does not protect the program from segmentation faults caused by attempts to read beyond the end of a buffer. RecommendationUpdate the and-expression so that the range check precedes the array offset. This will ensure that the bounds are checked before the array is accessed. ExampleThe int find(int start, char *str, char goal)
{
int len = strlen(str);
//Potential buffer overflow
for (int i = start; str[i] != 0 && i < len; i++) {
if (str[i] == goal)
return i;
}
return -1;
}
int findRangeCheck(int start, char *str, char goal)
{
int len = strlen(str);
//Range check protects against buffer overflow
for (int i = start; i < len && str[i] != 0 ; i++) {
if (str[i] == goal)
return i;
}
return -1;
}
Update the and-expression so that the range check precedes the array offset (for example, the References
cpp/ql/src/Best Practices/Likely Errors/Slicing.qhelpSlicingThis query finds assignments of a non-reference instance of a derived type to a variable of the base type where the derived type has more fields than the base. These assignments slice off all the fields added by the derived type, and can cause unexpected state when accessed as the derived type. RecommendationChange the type of the variable at the left-hand side of the assignment to the subclass. Examplestatic int idctr = 0;
//Basic connection with id
class Connection {
public:
int connId;
virtual void print_info() {
cout << "id: " << connId << "\n";
}
Connection() {
connId = idctr++;
}
};
//Adds counters, and an overriding print_info
class MeteredConnection : public Connection {
public:
int txCtr;
int rxCtr;
MeteredConnection() {
txCtr = 0;
rxCtr = 0;
}
virtual void print_info() {
cout << "id: " << connId << "\n" << "tx/rx: " << txCtr << "/" << rxCtr << "\n";
}
};
int main(int argc, char* argv[]) {
Connection conn;
MeteredConnection m_conn;
Connection curr_conn = conn;
curr_conn.print_info();
curr_conn = m_conn; //Wrong: Derived MetricConnection assigned to Connection
//variable, will slice off the counters and the overriding print_info
curr_conn.print_info(); //Will not print the counters.
Connection* curr_pconn = &conn;
curr_pconn->print_info();
curr_pconn = &m_conn; //Correct: Pointer assigned to address of the MetricConnection.
//Counters and virtual functions remain intact.
curr_pconn->print_info(); //Will call the correct method MeteredConnection::print_info
}
References
cpp/ql/src/Best Practices/Magic Constants/MagicConstantsNumbers.qhelpMagic numbersA magic number is a numeric literal (for example,
RecommendationConsider creating a Examplevoid sanitize(Fields[] record) {
//The number of fields here can be put in a const
for (fieldCtr = 0; field < 7; field++) {
sanitize(fields[fieldCtr]);
}
}
#define NUM_FIELDS 7
void process(Fields[] record) {
//This avoids using a magic constant by using the macro instead
for (fieldCtr = 0; field < NUM_FIELDS; field++) {
process(fields[fieldCtr]);
}
}
References
cpp/ql/src/Best Practices/Magic Constants/MagicConstantsString.qhelpMagic stringsA magic string is a string literal (for example,
RecommendationConsider replacing the magic string with a new named constant. References
cpp/ql/src/Best Practices/RuleOfThree.qhelpRule of threeThis query finds classes that define a destructor, a copy constructor, or a copy assignment operator, but not all three of them. The compiler generates default implementations for these functions, and since they deal with similar concerns it is likely that if the default implementation of one of them is not satisfactory, then neither are those of the others. The query flags any such class with a warning, and also display the list of generated warnings in the result view. RecommendationExplicitly define the missing functions. References
cpp/ql/src/Best Practices/RuleOfTwo.qhelpInconsistent definition of copy constructor and assignment ('Rule of Two')This rule finds classes that define a copy constructor or a copy assignment operator, but not both of them. The compiler generates default implementations for these functions, and since they deal with similar concerns it is likely that if the default implementation of one of them is not satisfactory, then neither is that of the other. When a class defines a copy constructor or a copy assignment operator, but not both, this can cause unexpected behavior. The object initialization (that is, RecommendationFirst, consider whether the user-defined member needs to be explicitly defined at all. If no user-defined copy constructor is provided for a class, the compiler will always attempt to generate a public copy constructor that recursively invokes the copy constructor of each field. If the existing user-defined copy constructor does exactly the same, it is most likely beneficial to delete it. The compiler-generated version may be more efficient, and it does not need to be manually maintained as fields are added and deleted. If the user-defined member does need to exist, the other corresponding member should be defined too. It can be defined as defaulted (using Exampleclass C {
private:
Other* other = NULL;
public:
C(const C& copyFrom) {
Other* newOther = new Other();
*newOther = copyFrom.other;
this->other = newOther;
}
//No operator=, by default will just copy the pointer other, will not create a new object
};
class D {
Other* other = NULL;
public:
D& operator=(D& rhs) {
Other* newOther = new Other();
*newOther = rhs.other;
this->other = newOther;
return *this;
}
//No copy constructor, will just copy the pointer other and not create a new object
};
References
cpp/ql/src/Documentation/DocumentApi.qhelpUndocumented API functionFunctions that are called from lots of different places are usually important, and justify having documentation written for them. In particular, if a function is defined in a file, and is called from at least two other files, then the function should probably be documented. As an exception, because their purpose is usually obvious, it is not necessary to document constructors, destructors, implementations of RecommendationAdd comments to document the purpose of the function. In particular, ensure that the public API of the function is carefully documented. This reduces the chance that a future change to the function will introduce a defect by changing the API and breaking the expectations of the calling functions. References
cpp/ql/src/Documentation/FixmeComments.qhelpFIXME commentThe indicated comment is a FIXME comment. FIXME comments are often used to indicate code that does not work correctly or that may not work in all supported environments. This may be necessary during the implementation of new functionality but FIXME comments should not be present in stable code. Any FIXME comments should be reviewed and the code improved as soon as possible to avoid the accumulation of partially implemented features. RecommendationFix the functionality indicated by the comment. If the comment no longer applies, delete it to avoid confusion. Exampleint isEven(int n) {
//FIXME: Is only correct for small values of n
return n == 0 || n == 2;
}References
cpp/ql/src/Documentation/TodoComments.qhelpTODO commentThe indicated comment is a TODO comment. TODO comments are often used to indicate code that is incomplete. This may be necessary during the implementation of new functionality but TODO comments should not be present in stable code. Any TODO comments should be reviewed and the code completed as soon as possible to avoid the accumulation of partially implemented features. RecommendationImplement the functionality indicated by the comment. If the comment no longer applies, delete it to avoid confusion. Exampleint isOdd(int n) {
//TODO: Works only for positive n. Need to check if negative n is valid input
return (n % 2) == 1;
}References
cpp/ql/src/Documentation/UncommentedFunction.qhelpPoorly documented large functionThis rule finds large functions that have too few comment lines. Documentation becomes more important as a function becomes more complex, and a lack of documentation makes it harder to maintain. RecommendationAdd comments to document the purpose of the function. Large, complex functions in particular require detailed documentation, not only because they are harder to understand, but the process of documentation may reveal that the function could be split into smaller, more cohesive functions. Referencescpp/ql/src/Header Cleanup/Cleanup-DuplicateIncludeGuard.qhelpDuplicate include guardA common pattern in header files is to use pre-processor directives to guard a header file against being processed more than once per translation unit. This practice is intended to prevent compilation errors. However, pre-processor include guards are prone to human error themselves because each include guard must be assigned a unique macro name to function correctly. If two header files share the same guard macro, the compiler may unexpectedly skip the second file it encounters, leading to compilation errors or configuration bugs. The query will flag the pre-processor RecommendationFirst decide whether the duplicate include guard is dangerous. A duplicate include guard may cause the header file to be skipped over when it shouldn't be, but occasionally this design is used on purpose to 'override' an existing header file. To address the issue, rename the macros used by all but one instance of the duplicate include guard. Remember to change both the ExampleHere's an example of two header files that have accidentally been given the same include guard macro. To fix the issue, rename both occurrences of the macro in the second file, for example to ANOTHER_HEADER_FILE_H. // header_file.h
#ifndef HEADER_FILE_H
#define HEADER_FILE_H
// ...
#endif // HEADER_FILE_H// another_header_file.h
#ifndef HEADER_FILE_H // should be ANOTHER_HEADER_FILE_H
#define HEADER_FILE_H // should be ANOTHER_HEADER_FILE_H
// ...
#endif // HEADER_FILE_HReferences
cpp/ql/src/Likely Bugs/Arithmetic/BadCheckOdd.qhelpBad check for oddnessThis rule finds code that uses RecommendationConsider using References
cpp/ql/src/Likely Bugs/Likely Typos/AssignWhereCompareMeant.qhelpAssignment where comparison was intendedThis rule finds uses of the assignment operator The rule flags every occurrence of an assignment in a position where its result is interpreted as a truth value. An assignment is only flagged if its right hand side is a compile-time constant. RecommendationCheck to ensure that the flagged expressions are not typos. If an assignment is really intended to be treated as a truth value, it may be better to surround it with parentheses. Exampleif(p = NULL) { //most likely == was intended. Otherwise it evaluates to the value
//of the rhs of the assignment (which is NULL)
...
}
References
cpp/ql/src/Likely Bugs/Likely Typos/CompareWhereAssignMeant.qhelpComparison where assignment was intendedThis rule finds uses of the equality operator The rule flags every occurrence of an equality operator in a position where its result is discarded. RecommendationCheck to ensure that the flagged expressions are not typos. If the result of an equality test is really intended to be discarded, it should be explicitly cast to Exampleint x;
x == 4; // most likely = was intended. Otherwise this statement has no effect.
...
References
cpp/ql/src/Likely Bugs/OO/IncorrectConstructorDelegation.qhelpIncorrect constructor delegationPrior to C++11, there is no mechanism for a constructor to delegate part of the object initialization to another, although other languages provide this feature. Consequently, any instance where a constructor call appears in the body of a constructor without being used is suspect. RecommendationThe rule flags constructor calls in constructors which are not used in some way. This is usually a misguided attempt to share some initialization code between multiple constructors, or to provide sensible defaults for some constructor parameters. The effect of a flagged expression would be to initialize an instance of the current class on the stack, and then let it go out of scope at the end of the constructor call. There are several ways to address the underlying issue of sharing initialization code, and the most appropriate needs to picked in each case. Roughly speaking, the options are:
Exampleclass Circle {
private:
double m_x;
double m_y;
double m_radius;
double m_area;
public:
// Real constructor:
Circle(double x, double y, double radius) :
m_x(x), m_y(y), m_radius(radius)
{
m_area = 3.14159 * m_radius * m_radius;
}
Circle() {
// WRONG: Attempt to define the unit circle by default fails.
Circle(0, 0, 1);
}
};
References
cpp/ql/src/Metrics/Files/FCommentRatio.qhelpPercentage of commentsThis metric measures the percentage of lines in a file that contain a comment or are part of a multi-line comment. Having a low percentage of comments is an indication that a file does not have sufficient documentation. Undocumented code is hard to understand, modify, and reuse. RecommendationAdd documentation to files with a low percentage of comments. It is most useful to start documenting the public functions first. Referencescpp/ql/src/Metrics/Files/FCyclomaticComplexity.qhelpAverage cyclomatic complexity of filesThis metric measures the average cyclomatic complexity of the functions in a file. The cyclomatic complexity of a function is the number of linearly independent execution paths through that function. A path is linearly independent path if it differs from all other paths by at least one node. Straight-line code therefore has a cyclomatic complexity of one, while branches, switches and loops increase cyclomatic complexity. Functions with a high cyclomatic complexity are typically hard to understand and test. By extension, files whose functions have a high average cyclomatic complexity are problematic, and usually would benefit from refactoring. As a concrete example, consider the following function: int f(int i, int j) {
// start
int result;
if(i % 2 == 0) {
// iEven
result = i + j;
}
else {
// iOdd
if(j % 2 == 0) {
// jEven
result = i * j;
}
else {
// jOdd
result = i - j;
}
}
return result;
// end
}The control flow graph for this function is as follows:
RecommendationFunctions with a high cyclomatic complexity should be simplified, for instance by tidying up any complex logic within them or by splitting them into multiple methods using the Extract Method refactoring. References
cpp/ql/src/Metrics/Files/FLinesOfCode.qhelpLines of code in filesThis metric measures the number of lines of code in a file. This excludes comments and blank lines. Having too many lines of code in a file is an indication that it can be split into several files of more manageable size. Generated code is a notable exception to this. RecommendationLong files should be examined to see if they can be split into smaller, more cohesive files. References
cpp/ql/src/Metrics/Files/FLinesOfComments.qhelpLines of comments in filesThis metric measures the number of lines of comments in a file. Files that have too few comments are more likely to be insufficiently documented. Long files that have no comments at all require particular scrutiny, as these are more likely to need explicit documentation in comments. RecommendationFiles with few to no comments should be examined to see if they require documentation. Particular attention should be given to long files. Referencescpp/ql/src/Metrics/Files/FTodoComments.qhelpNumber of todo/fixme comments per fileThis metric measures the number of TODO or FIXME comments in the code. These comments tend to document points of ambiguity in the software's requirements. Often they refer to corner-cases that are not handled or potential defects. It is therefore very important to monitor such comments and, where appropriate, escalate comments to an defect-tracking system or other means of ensuring that action is taken. RecommendationRemove unnecessary TODO/FIXME comments, and those that are no longer relevant. File tickets for the remaining comments in a defect-tracker, or otherwise ensure that someone is responsible for fixing them. Referencescpp/ql/src/Metrics/Functions/FunLinesOfComments.qhelpLines of comments per functionThis metric measures the number of lines of comments in a function. Functions that have too few comments are more likely to be insufficiently documented. Long, complex functions that have no comments at all require particular scrutiny, as these are more likely to need explicit documentation in comments. RecommendationFunctions with few to no comments should be examined to see if they require documentation. Particular attention should be given to long, complex functions. Referencescpp/ql/src/Metrics/Functions/FunPercentageOfComments.qhelpComment ratio per functionThis metric measures the percentage of lines in an function that contain a comment or are part of a multi-line comment. Having a low comment ratio is an indication that a function does not have sufficient documentation. RecommendationStart by adding documentation to functions that are used from other parts of the code. Then document large complex functions, as they benefit most from documentation. Referencescpp/ql/src/Security/CWE/CWE-079/CgiXss.qhelpCGI script vulnerable to cross-site scriptingDirectly writing an HTTP request parameter back to a web page allows for a cross-site scripting vulnerability. The data is displayed in a user's web browser as belonging to one site, but it is provided by some other site that the user browses to. In effect, such an attack allows one web site to insert content in the other one. For web servers implemented with the Common Gateway Interface (CGI), HTTP parameters are supplied via the RecommendationTo guard against cross-site scripting, consider escaping special characters before writing the HTTP parameter back to the page. ExampleIn the following example, the void bad_server() {
char* query = getenv("QUERY_STRING");
puts("<p>Query results for ");
// BAD: Printing out an HTTP parameter with no escaping
puts(query);
puts("\n<p>\n");
puts(do_search(query));
}
void good_server() {
char* query = getenv("QUERY_STRING");
puts("<p>Query results for ");
// GOOD: Escape HTML characters before adding to a page
char* query_escaped = escape_html(query);
puts(query_escaped);
free(query_escaped);
puts("\n<p>\n");
puts(do_search(query));
}References
cpp/ql/src/Security/CWE/CWE-676/DangerousFunctionOverflow.qhelpUse of dangerous functionThis rule finds calls to the The RecommendationReplace calls to ExampleThe following example gets a string from standard input in two ways: #define BUFFERSIZE (1024)
// BAD: using gets
void echo_bad() {
char buffer[BUFFERSIZE];
gets(buffer);
printf("Input was: '%s'\n", buffer);
}
// GOOD: using fgets
void echo_good() {
char buffer[BUFFERSIZE];
fgets(buffer, BUFFERSIZE, stdin);
printf("Input was: '%s'\n", buffer);
}The first version uses Related rulesOther dangerous functions identified by CWE-676 ("Use of Potentially Dangerous Function") include References
cpp/ql/src/jsf/4.10 Classes/AV Rule 79.qhelpResource not released in destructorThis rule finds resources that are allocated by a class, but not released in the destructor of that class. Allocating a resource includes:
RecommendationIf the resource is not being released at all, ensure that the class does release the resource, normally by adding the release to the destructor of the class. This change needs to be carefully validated: client code may be relying on the resource outliving the class that allocated it, and must be reviewed and updated if necessary. In the other case, for instance a class that has an explicit
Example// This class opens a file but never closes it. Even its clients
// cannot close the file
class ResourceLeak {
private:
int sockfd;
FILE* file;
public:
C() {
sockfd = socket(AF_INET, SOCK_STREAM, 0);
}
void f() {
file = fopen("foo.txt", "r");
...
}
};
// This class relies on its client to release any stream it
// allocates. Note that this means the client must have
// intimate knowledge of the implementation of the class to
// decide whether it is safe to release the stream.
class StreamPool {
private:
Stream *instance;
public:
Stream *createStream(char *name) {
if (!instance)
instance = new Stream(name);
return instance;
}
}
// This class handles its resources, but does not do that in
// the constructor/destructor. It can be rewritten easily to
// be safer to use.
class StreamHandler {
private:
char *_name;
Stream *stream;
public:
C(char *name) {
_name = strdup(name):
}
void open() {
stream = new Stream();
}
void close() {
delete stream;
}
~StreamHandler() {
free(_name);
// stream should be deleted here, not in close()
}
}References
csharp/ql/src/Bad Practices/CallsUnmanagedCode.qhelpCalls to unmanaged codeMicrosoft defines two broad categories for source code. Managed code compiles into bytecode and is then executed by a virtual machine. Unmanaged code is compiled directly into machine code. All C# code is managed but it is possible to call external unmanaged code. This rule finds calls to RecommendationConsider whether the calls could be replaced by calls to managed code instead. ExampleThis example shows a function that displays a message box when clicked. It is implemented with unmanaged code from the User32.dll library. using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
public partial class UnmanagedCodeExample : Form
{
[DllImport("User32.dll")]
public static extern int MessageBox(int h, string m, string c, int type);
private void btnSayHello_Click(object sender, EventArgs e)
{
MessageBox(0, "Hello World", "Title", 0); // BAD
}
}Fixing by Using Managed CodeThis code example does the exact same thing except it uses managed code to do so. using System;
using System.Windows.Forms;
public partial class ManagedCodeExample : Form
{
private void btnSayHello_Click(object sender, EventArgs e)
{
MessageBox.Show("Hello World", "Title");
}
}References
csharp/ql/src/Bad Practices/Comments/TodoComments.qhelpTODO commentA comment that includes the words RecommendationAddress the problem indicated by the comment. ExampleIn the following example, the programmer has not yet implemented the correct behavior for the case where parameter using System;
class Bad
{
public static double SolveQuadratic(double a, double b, double c)
{
// TODO: handle case where a == 0
return (-b + Math.Sqrt(b * b - 4 * a * c)) / (2 * a);
}
}As a first step to fixing this problem, a check could be introduced that compares References
csharp/ql/src/Bad Practices/Declarations/EmptyInterface.qhelpEmpty interfaceEmpty interfaces are often used as a way of marking particular classes. RecommendationIn some languages, using a marker interface is a useful design pattern, but in C# it is better to use custom attributes. Marker interfaces are always inherited and so they cannot be applied to a single class without applying it to all subclasses. Custom attributes do not have this limitation. ExampleIn this example, the using System;
class Bad
{
interface IsPrintable { }
class Form1 : IsPrintable { }
}The following example is better because it uses attributes instead. using System;
class Good
{
[AttributeUsage(AttributeTargets.Class)]
class PrintableAttribute : Attribute { }
[Printable]
class Form1 { }
}References
csharp/ql/src/Bad Practices/UnmanagedCodeCheck.qhelpUnmanaged codeMicrosoft defines two broad categories for source code. Managed code compiles into bytecode and is then executed by a virtual machine. Unmanaged code is compiled directly into machine code. All C# code is managed but it is possible to call external unmanaged code. This rule finds RecommendationConsider whether the unmanaged ExampleThis example shows a function that displays a message box when clicked. The unmanaged code is shown first and then the same function being performed by managed code is shown after. // example of using unmanaged code
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
public partial class UnmanagedCodeExample : Form
{
[DllImport("User32.dll")]
public static extern int MessageBox(int h, string m, string c, int type); // BAD
private void btnSayHello_Click(object sender, EventArgs e)
{
MessageBox(0, "Hello World", "Title", 0);
}
}
// the same thing in managed code
using System;
using System.Windows.Forms;
public partial class ManagedCodeExample : Form
{
private void btnSayHello_Click(object sender, EventArgs e)
{
MessageBox.Show("Hello World", "Title");
}
}References
csharp/ql/src/Dead Code/DeadStoreOfLocal.qhelpUseless assignment to local variableA value is assigned to a local variable, but either that variable is never read later on, or its value is always overwritten before being read. This means that the original assignment has no effect, and could indicate a logic error or incomplete code. RecommendationEnsure that you check the program logic carefully. If a value is really not needed, consider omitting the assignment. Be careful, though: if the right-hand side has a side effect (like performing a method call), it is important to keep this to preserve the overall behavior. ExampleThe following example shows six different types of assignments to local variables whose value is not read:
using System;
class Bad
{
double ParseInt(string s)
{
var success = int.TryParse(s, out int i);
return i;
}
bool IsDouble(string s)
{
var success = double.TryParse(s, out double i);
return success;
}
double ParseDouble(string s)
{
try
{
return double.Parse(s);
}
catch (FormatException e)
{
return double.NaN;
}
}
int Count(string[] ss)
{
int count = 0;
foreach (var s in ss)
count++;
return count;
}
string IsInt(object o)
{
if (o is int i)
return "yes";
else
return "no";
}
string IsString(object o)
{
switch (o)
{
case string s:
return "yes";
default:
return "no";
}
}
}The revised example eliminates the unread assignments. using System;
class Good
{
double ParseInt(string s)
{
int.TryParse(s, out int i);
return i;
}
bool IsDouble(string s)
{
var success = double.TryParse(s, out _);
return success;
}
double ParseDouble(string s)
{
try
{
return double.Parse(s);
}
catch (FormatException)
{
return double.NaN;
}
}
int Count(string[] ss)
{
return ss.Length;
}
string IsInt(object o)
{
if (o is int)
return "yes";
else
return "no";
}
string IsString(object o)
{
switch (o)
{
case string _:
return "yes";
default:
return "no";
}
}
}References
csharp/ql/src/Likely Bugs/BadCheckOdd.qhelpBad parity checkAvoid using RecommendationConsider using Example-9 is an odd number but this example does not detect it as one. This is because class CheckOdd
{
private static bool IsOdd(int x)
{
return x % 2 == 1;
}
public static void Main(String[] args)
{
Console.Out.WriteLine(IsOdd(-9)); // prints False
}
}It would be better to check if the number is even and then invert that check. class CheckOdd
{
private static bool IsOdd(int x)
{
return x % 2 != 0;
}
public static void Main(String[] args)
{
Console.Out.WriteLine(IsOdd(-9)); // prints True
}
}References
csharp/ql/src/Metrics/Callables/CCyclomaticComplexity.qhelpCyclomatic complexity of functionsThis metric measures the number of linearly independent execution paths through methods. Linearly independent paths are calculated using the control flow diagram for a piece of code. A linearly independent path includes at least one new edge that has not been included in any linearly independent path counted so far. Methods with a high cyclomatic complexity can be difficult to understand and difficult to test because there are so many different ways they could execute. Consider this method: public static void foo(int count)
{
if (count > 10) {
Console.WriteLine("The count is large");
}
var timesLeft = count;
while (timesLeft > 0) {
switch(Console.ReadLine()) {
case "BYE" : Console.WriteLine("Good bye"); break;
case "HELLO" : Console.WriteLine("Hi"); break;
case "HELP" : Console.WriteLine("Try HELLO or BYE."); break;
default : Console.WriteLine("Input not understood."); break;
}
timesLeft--;
}
}The control flow diagram for through this method looks like this:
RecommendationComplex methods should have parts of their functionality extracted to helper methods. This makes testing easier because each helper method can be tested individually. References
csharp/ql/src/Metrics/Files/FCyclomaticComplexity.qhelpAverage cyclomatic complexity of filesThis metric measures the average cyclomatic complexity of the functions in a file. The cyclomatic complexity of a function is the number of linearly independent execution paths through that function. A path is linearly independent path if it differs from all other paths by at least one node. Straight-line code therefore has a cyclomatic complexity of one, while branches, switches and loops increase cyclomatic complexity. Functions with a high cyclomatic complexity are typically hard to understand and test. By extension, files whose functions have a high average cyclomatic complexity are problematic, and usually would benefit from refactoring. As a concrete example, consider the following function: int f(int i, int j) {
// start
int result;
if(i % 2 == 0) {
// iEven
result = i + j;
}
else {
// iOdd
if(j % 2 == 0) {
// jEven
result = i * j;
}
else {
// jOdd
result = i - j;
}
}
return result;
// end
}The control flow graph for this function is as follows:
RecommendationFunctions with a high cyclomatic complexity should be simplified, for instance by tidying up any complex logic within them or by splitting them into multiple methods using the Extract Method refactoring. References
csharp/ql/src/Metrics/Files/FSelfContainedness.qhelpSelf containedness of filesThis metric measures the percentage of types on which the file depends for which the build process built from source. The availability of source code is one of the key factors that affects how easy a project will be to build for different versions of the .NET framework. Files with low self-containedness are also more affected by changes to their dependencies. RecommendationDepending on your project, self-containedness may or may not be an issue for you. If you decide that it should be addressed then there are a few things you can do to easily increase self-containedness. One way of increasing self-containedness is by creating wrappers for any external classes. If the external class is changed then only your wrapper needs to be updated. You should also try to use libraries with source code available. References
csharp/ql/src/Metrics/RefTypes/TUnmanagedCode.qhelpTypes containing unmanaged codeMicrosoft defines two broad categories for source code. Managed code compiles into bytecode and is then executed by a virtual machine. Unmanaged code is compiled directly into machine code. All C# code is managed but it is possible to call external unmanaged code. This metric counts the number of RecommendationConsider whether the unmanaged methods could be replaced by managed code instead. ExampleThis example shows a function that displays a message box when clicked. It is implemented with unmanaged code from the using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
public partial class UnmanagedCodeExample : Form
{
[DllImport("User32.dll")]
public static extern int MessageBox(int h, string m, string c, int type); // violation
private void btnSayHello_Click(object sender, EventArgs e)
{
MessageBox(0, "Hello World", "Title", 0);
}
}Fixing by Using Managed CodeThis example uses managed code to perform the same function. using System;
using System.Windows.Forms;
public partial class ManagedCodeExample : Form
{
private void btnSayHello_Click(object sender, EventArgs e)
{
MessageBox.Show("Hello World", "Title");
}
}References
csharp/ql/src/Security Features/CWE-079/XSS.qhelpCross-site scriptingDirectly writing user input (for example, an HTTP request parameter) to a webpage, without properly sanitizing the input first, allows for a cross-site scripting vulnerability. RecommendationTo guard against cross-site scripting, consider using a library that provides suitable encoding functionality, such as the ExampleThe following example shows the page parameter being written directly to the server error page, leaving the website vulnerable to cross-site scripting. using System;
using System.Web;
public class XSSHandler : IHttpHandler
{
public void ProcessRequest(HttpContext ctx)
{
ctx.Response.Write(
"The page \"" + ctx.Request.QueryString["page"] + "\" was not found.");
}
}Sanitizing the user-controlled data using the using System;
using System.Web;
using System.Net;
public class XSSHandler : IHttpHandler
{
public void ProcessRequest(HttpContext ctx)
{
string page = WebUtility.HtmlEncode(ctx.Request.QueryString["page"]);
ctx.Response.Write(
"The page \"" + page + "\" was not found.");
}
}References
csharp/ql/src/Security Features/InadequateRSAPadding.qhelpWeak encryption: inadequate RSA paddingThis query finds uses of RSA encryption without secure padding. Using PKCS#1 v1.5 padding can open up your application to several different attacks resulting in the exposure of the encryption key or the ability to determine plaintext from encrypted messages. RecommendationUse the more secure PKCS#1 v2 (OAEP) padding. References
csharp/ql/src/Security Features/InsecureRandomness.qhelpInsecure randomnessUsing a cryptographically weak pseudo-random number generator to generate a security-sensitive value, such as a password, makes it easier for an attacker to predict the value. Pseudo-random number generators generate a sequence of numbers that only approximates the properties of random numbers. The sequence is not truly random because it is completely determined by a relatively small set of initial values, the seed. If the random number generator is cryptographically weak, then this sequence may be easily predictable through outside observations. RecommendationUse a cryptographically secure pseudo-random number generator if the output is to be used in a security sensitive context. As a rule of thumb, a value should be considered "security sensitive" if predicting it would allow the attacker to perform an action that they would otherwise be unable to perform. For example, if an attacker could predict the random password generated for a new user, they would be able to log in as that new user. For C#, ExampleThe following examples show different ways of generating a password. In the first case, we generate a fresh password by appending a random integer to the end of a static string. The random number generator used ( In the second example, a cryptographically secure random number generator is used for the same purpose. In this case, it is much harder to predict the generated integers. In the final example, the password is generated using the using System.Security.Cryptography;
using System.Web.Security;
string GeneratePassword()
{
// BAD: Password is generated using a cryptographically insecure RNG
Random gen = new Random();
string password = "mypassword" + gen.Next();
// GOOD: Password is generated using a cryptographically secure RNG
using (RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider())
{
byte[] randomBytes = new byte[sizeof(int)];
crypto.GetBytes(randomBytes);
password = "mypassword" + BitConverter.ToInt32(randomBytes);
}
// BAD: Membership.GeneratePassword generates a password with a bias
password = Membership.GeneratePassword(12, 3);
return password;
}References
csharp/ql/src/Security Features/InsufficientKeySize.qhelpWeak encryption: Insufficient key sizeThis rule finds uses of encryption algorithms with too small a key size. Encryption algorithms are vulnerable to brute force attack when too small a key size is used. RecommendationThe key should be at least 2048-bit long when using RSA encryption, and 128-bit long when using symmetric encryption. Referencescsharp/ql/src/Security Features/WeakEncryption.qhelpWeak encryptionWeak encryption algorithms provide very little security. For example DES encryption uses keys of 56 bits only, and no longer provides sufficient protection for sensitive data. TripleDES should also be deprecated for very sensitive data: Although it improves on DES by using 168-bit long keys, it provides in fact at most 112 bits of security. RecommendationYou should switch to a more secure encryption algorithm, such as AES (Advanced Encryption Standard) and use a key length which is reasonable for the application for which it is being used. Do not use the ECB encryption mode since it is vulnerable to replay and other attacks. ExampleThis example uses DES, which is limited to a 56-bit key. The key provided is actually 64 bits but the last bit of each byte is turned into a parity bit. For example the bytes 01010101 and 01010100 can be used in place of each other when encrypting and decrypting. class WeakEncryption
{
public static byte[] encryptString()
{
SymmetricAlgorithm serviceProvider = new DESCryptoServiceProvider();
byte[] key = { 16, 22, 240, 11, 18, 150, 192, 21 };
serviceProvider.Key = key;
ICryptoTransform encryptor = serviceProvider.CreateEncryptor();
String message = "Hello World";
byte[] messageB = System.Text.Encoding.ASCII.GetBytes(message);
return encryptor.TransformFinalBlock(messageB, 0, messageB.Length);
}
}Referencesgo/ql/src/RedundantCode/DeadStoreOfLocal.qhelpUseless assignment to local variableA value is assigned to a variable, but either it is never read, or its value is always overwritten before being read. This means that the original assignment has no effect, and could indicate a logic error or incomplete code. RecommendationRemove assignments to variables that are immediately overwritten, or use the blank identifier ExampleIn the following example, a value is assigned to package main
import "fmt"
func main() {
a := calculateValue()
a = 2
b := calculateValue()
ignore, ignore1 := fmt.Println(a)
ignore, ignore1, err := function()
if err != nil {
panic(err)
}
fmt.Println(a)
}The result of package main
import "fmt"
func main() {
a := 2
fmt.Println(a)
_, _, err := function()
if err != nil {
panic(err)
}
fmt.Println(a)
}References
go/ql/src/RedundantCode/UnreachableStatement.qhelpUnreachable statementAn unreachable statement often indicates missing code or a latent bug and should be examined carefully. RecommendationExamine the surrounding code to determine why the statement has become unreachable. If it is no longer needed, remove the statement. ExampleIn the following example, the body of the package main
func mul(xs []int) int {
res := 1
for i := 0; i < len(xs); i++ {
x := xs[i]
res *= x
if res == 0 {
}
return 0
}
return res
}Most likely, the package main
func mulGood(xs []int) int {
res := 1
for i := 0; i < len(xs); i++ {
x := xs[i]
res *= x
if res == 0 {
return 0
}
}
return res
}References
go/ql/src/Security/CWE-079/ReflectedXss.qhelpReflected cross-site scriptingDirectly writing user input (for example, an HTTP request parameter) to an HTTP response without properly sanitizing the input first, allows for a cross-site scripting vulnerability. This kind of vulnerability is also called reflected cross-site scripting, to distinguish it from other types of cross-site scripting. RecommendationTo guard against cross-site scripting, consider using contextual output encoding/escaping before writing user input to the response, or one of the other solutions that are mentioned in the references. ExampleThe following example code writes part of an HTTP request (which is controlled by the user) directly to the response. This leaves the website vulnerable to cross-site scripting. package main
import (
"fmt"
"net/http"
)
func serve() {
http.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
username := r.Form.Get("username")
if !isValidUsername(username) {
// BAD: a request parameter is incorporated without validation into the response
fmt.Fprintf(w, "%q is an unknown user", username)
} else {
// TODO: Handle successful login
}
})
http.ListenAndServe(":80", nil)
}Sanitizing the user-controlled data prevents the vulnerability: package main
import (
"fmt"
"html"
"net/http"
)
func serve1() {
http.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
username := r.Form.Get("username")
if !isValidUsername(username) {
// GOOD: a request parameter is escaped before being put into the response
fmt.Fprintf(w, "%q is an unknown user", html.EscapeString(username))
} else {
// TODO: do something exciting
}
})
http.ListenAndServe(":80", nil)
}References
go/ql/src/Security/CWE-079/StoredXss.qhelpStored cross-site scriptingDirectly using externally-controlled stored values (for example, file names or database contents) to create HTML content without properly sanitizing the input first, allows for a cross-site scripting vulnerability. This kind of vulnerability is also called stored cross-site scripting, to distinguish it from other types of cross-site scripting. RecommendationTo guard against cross-site scripting, consider using contextual output encoding/escaping before using uncontrolled stored values to create HTML content, or one of the other solutions that are mentioned in the references. ExampleThe following example code writes file names directly to an HTTP response. This leaves the website vulnerable to cross-site scripting, if an attacker can choose the file names on the disk. package main
import (
"io"
"net/http"
"os"
)
func ListFiles(w http.ResponseWriter, r *http.Request) {
files, _ := os.ReadDir(".")
for _, file := range files {
io.WriteString(w, file.Name()+"\n")
}
}Sanitizing the file names prevents the vulnerability: package main
import (
"html"
"io"
"net/http"
"os"
)
func ListFiles1(w http.ResponseWriter, r *http.Request) {
files, _ := os.ReadDir(".")
for _, file := range files {
io.WriteString(w, html.EscapeString(file.Name())+"\n")
}
}References
go/ql/src/Security/CWE-338/InsecureRandomness.qhelpUse of insufficient randomness as the key of a cryptographic algorithmUsing a cryptographically weak pseudo-random number generator to generate a security-sensitive value, such as a password, makes it easier for an attacker to predict the value. Pseudo-random number generators generate a sequence of numbers that only approximates the properties of random numbers. The sequence is not truly random because it is completely determined by a relatively small set of initial values, the seed. If the random number generator is cryptographically weak, then this sequence may be easily predictable through outside observations. RecommendationUse a cryptographically secure pseudo-random number generator if the output is to be used in a security sensitive context. As a rule of thumb, a value should be considered "security sensitive" if predicting it would allow the attacker to perform an action that they would otherwise be unable to perform. For example, if an attacker could predict the random password generated for a new user, they would be able to log in as that new user. For Go, ExampleThe example below uses the package main
import (
"math/rand"
)
var charset = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
func generatePassword() string {
s := make([]rune, 20)
for i := range s {
s[i] = charset[rand.Intn(len(charset))]
}
return string(s)
}Instead, use package main
import (
"crypto/rand"
"math/big"
)
func generatePasswordGood() string {
s := make([]rune, 20)
for i := range s {
idx, err := rand.Int(rand.Reader, big.NewInt(int64(len(charset))))
if err != nil {
// handle err
}
s[i] = charset[idx.Int64()]
}
return string(s)
}References
java/ql/src/Likely Bugs/Concurrency/LazyInitStaticField.qhelpIncorrect lazy initialization of a static fieldThe tactic of initializing a static field the first time it is used, known as "lazy initialization", can be problematic in a multi-threaded context when used without proper synchronization. If a separate thread starts executing before the field is initialized, the thread may see an incompletely initialized object. RecommendationIf lazy initialization is desirable for performance reasons, the best solution is usually to declare the enclosing method ExampleIn the following example, the static field class Singleton {
private static Resource resource;
public Resource getResource() {
if(resource == null)
resource = new Resource(); // Lazily initialize "resource"
return resource;
}
}In the following modification of the above example, class Singleton {
private static Resource resource;
static {
resource = new Resource(); // Initialize "resource" only once
}
public Resource getResource() {
return resource;
}
}References
java/ql/src/Metrics/Callables/CCyclomaticComplexity.qhelpCyclomatic complexity of functionsThe cyclomatic complexity of a method (or constructor) is the number of possible linearly-independent execution paths through that method (see [Wikipedia]). It was originally introduced as a complexity measure by Thomas McCabe [McCabe]. A method with high cyclomatic complexity is typically difficult to understand and test. Exampleint f(int i, int j) {
int result;
if(i % 2 == 0) {
result = i + j;
}
else {
if(j % 2 == 0) {
result = i * j;
}
else {
result = i - j;
}
}
return result;
}The control flow graph for this method is as follows:
RecommendationSimplify methods that have a high cyclomatic complexity. For example, tidy up complex logic, and/or split methods into multiple smaller methods using the 'Extract Method' refactoring from [Fowler]. References
java/ql/src/Metrics/Files/FCyclomaticComplexity.qhelpAverage cyclomatic complexity of filesThis metric measures the average cyclomatic complexity of the functions in a file. The cyclomatic complexity of a function is the number of linearly independent execution paths through that function. A path is linearly independent path if it differs from all other paths by at least one node. Straight-line code therefore has a cyclomatic complexity of one, while branches, switches and loops increase cyclomatic complexity. Functions with a high cyclomatic complexity are typically hard to understand and test. By extension, files whose functions have a high average cyclomatic complexity are problematic, and usually would benefit from refactoring. As a concrete example, consider the following function: int f(int i, int j) {
// start
int result;
if(i % 2 == 0) {
// iEven
result = i + j;
}
else {
// iOdd
if(j % 2 == 0) {
// jEven
result = i * j;
}
else {
// jOdd
result = i - j;
}
}
return result;
// end
}The control flow graph for this function is as follows:
RecommendationFunctions with a high cyclomatic complexity should be simplified, for instance by tidying up any complex logic within them or by splitting them into multiple methods using the Extract Method refactoring. References
java/ql/src/Metrics/Files/FLinesOfDuplicatedCode.qhelpDuplicated lines in filesThis metric measures the number of lines in a file that are contained within a block that is duplicated elsewhere. These lines may include code, comments and whitespace, and the duplicate block may be in this file or in another file. A file that contains many lines that are duplicated within the code base is problematic for a number of reasons. Duplicated code increases overall code size, making the code base harder to maintain and harder to understand. It also becomes harder to fix bugs, since a programmer applying a fix to one copy has to always remember to update other copies accordingly. Finally, code duplication is generally an indication of a poorly designed or hastily written code base, which typically suffers from other problems as well. RecommendationRefactor files with lots of duplicated code to extract the common code into a shared library or module. References
java/ql/src/Metrics/Files/FLinesOfSimilarCode.qhelpSimilar lines in filesA file that contains many lines that are similar to other code within the code base is problematic for the same reasons as a file that contains a lot of (exactly) duplicated code. Duplicated code increases overall code size, making the code base harder to maintain and harder to understand. It also becomes harder to fix bugs, since a programmer applying a fix to one copy has to always remember to update other copies accordingly. Finally, code duplication is generally an indication of a poorly designed or hastily written code base, which typically suffers from other problems as well. RecommendationRefactor similar code snippets by extracting common functionality into methods that can be reused across classes. References
java/ql/src/Metrics/Files/FSelfContainedness.qhelpSelf-containedness of filesThis metric measures the percentage of the types on which a compilation unit depends for which we have source code available. The availability of source code is one of the key factors affecting how easy or difficult it will be to build a software project in the future, especially on platforms other than those for which it was originally developed. Projects will a high level of self-containedness are likely to be more portable and easier to build in ten years' time than those that depend on many binary-only, third-party libraries. (This is one reason why many of the dependencies of open-source projects are distributed as source code, aside from the fact that the binaries are generally larger and more unwieldy to distribute.) In the context of Java's platform independence, the availability of source code is less critical than it is for platform-dependent languages. However, note that there can be minor binary incompatibilities between different versions of Java. RecommendationLow self-containedness may or may not be a problem, depending on the context of your project. However, if you determine that it is an issue for you, it is best tackled at a project level, in the following ways:
References
java/ql/src/Metrics/RefTypes/TSelfContainedness.qhelpSelf-containedness of typesThis metric measures the percentage of the types on which a type depends for which we have source code available. The availability of source code is one of the key factors affecting how easy or difficult it will be to build a software project in the future, especially on platforms other than those for which it was originally developed. Projects will a high level of self-containedness are likely to be more portable and easier to build in ten years' time than those that depend on many binary-only, third-party libraries. (This is one reason why many of the dependencies of open-source projects are distributed as source code, aside from the fact that the binaries are generally larger and more unwieldy to distribute.) In the context of Java's platform independence, the availability of source code is less critical than it is for platform-dependent languages. However, note that there can be minor binary incompatibilities between different versions of Java. RecommendationLow self-containedness may or may not be a problem, depending on the context of your project. However, if you determine that it is an issue for you, it is best tackled at a project level, in the following ways:
References
java/ql/src/Security/CWE/CWE-079/XSS.qhelpCross-site scriptingDirectly writing user input (for example, an HTTP request parameter) to a web page, without properly sanitizing the input first, allows for a cross-site scripting vulnerability. RecommendationTo guard against cross-site scripting, consider using contextual output encoding/escaping before writing user input to the page, or one of the other solutions that are mentioned in the reference. ExampleThe following example shows the public class XSS extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// BAD: a request parameter is written directly to the Servlet response stream
response.getWriter().print(
"The page \"" + request.getParameter("page") + "\" was not found.");
}
}References
java/ql/src/Security/CWE/CWE-113/ResponseSplitting.qhelpHTTP response splittingDirectly writing user input (for example, an HTTP request parameter) to an HTTP header can lead to an HTTP request-splitting or response-splitting vulnerability. HTTP response splitting can lead to vulnerabilities such as XSS and cache poisoning. HTTP request splitting can allow an attacker to inject an additional HTTP request into a client's outgoing socket connection. This can allow an attacker to perform an SSRF-like attack. In the context of a servlet container, if the user input includes blank lines and the servlet container does not escape the blank lines, then a remote user can cause the response to turn into two separate responses. The remote user can then control one or more responses, which is also HTTP response splitting. RecommendationGuard against HTTP header splitting in the same way as guarding against cross-site scripting. Before passing any data into HTTP headers, either check the data for special characters, or escape any special characters that are present. If the code calls Netty API's directly, ensure that the ExampleThe following example shows the 'name' parameter being written to a cookie in two different ways. The first way writes it directly to the cookie, and thus is vulnerable to response-splitting attacks. The second way first removes all special characters, thus avoiding the potential problem. public class ResponseSplitting extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// BAD: setting a cookie with an unvalidated parameter
Cookie cookie = new Cookie("name", request.getParameter("name"));
response.addCookie(cookie);
// GOOD: remove special characters before putting them in the header
String name = removeSpecial(request.getParameter("name"));
Cookie cookie2 = new Cookie("name", name);
response.addCookie(cookie2);
}
private static String removeSpecial(String str) {
return str.replaceAll("[^a-zA-Z ]", "");
}
}ExampleThe following example shows the use of the library 'netty' with HTTP response-splitting verification configurations. The second way will verify the parameters before using them to build the HTTP response. import io.netty.handler.codec.http.DefaultHttpHeaders;
public class ResponseSplitting {
// BAD: Disables the internal response splitting verification
private final DefaultHttpHeaders badHeaders = new DefaultHttpHeaders(false);
// GOOD: Verifies headers passed don't contain CRLF characters
private final DefaultHttpHeaders goodHeaders = new DefaultHttpHeaders();
// BAD: Disables the internal response splitting verification
private final DefaultHttpResponse badResponse = new DefaultHttpResponse(version, httpResponseStatus, false);
// GOOD: Verifies headers passed don't contain CRLF characters
private final DefaultHttpResponse goodResponse = new DefaultHttpResponse(version, httpResponseStatus);
}ExampleThe following example shows the use of the netty library with configurations for verification of HTTP request splitting. The second recommended approach in the example verifies the parameters before using them to build the HTTP request. public class NettyRequestSplitting {
// BAD: Disables the internal request splitting verification
private final DefaultHttpHeaders badHeaders = new DefaultHttpHeaders(false);
// GOOD: Verifies headers passed don't contain CRLF characters
private final DefaultHttpHeaders goodHeaders = new DefaultHttpHeaders();
// BAD: Disables the internal request splitting verification
private final DefaultHttpRequest badRequest = new DefaultHttpRequest(httpVersion, method, uri, false);
// GOOD: Verifies headers passed don't contain CRLF characters
private final DefaultHttpRequest goodResponse = new DefaultHttpRequest(httpVersion, method, uri);
}References
java/ql/src/Security/CWE/CWE-326/InsufficientKeySize.qhelpUse of a cryptographic algorithm with insufficient key sizeModern encryption relies on the computational infeasibility of breaking a cipher and decoding its message without the key. As computational power increases, the ability to break ciphers grows, and key sizes need to become larger as a result. Cryptographic algorithms that use too small of a key size are vulnerable to brute force attacks, which can reveal sensitive data. RecommendationUse a key of the recommended size or larger. The key size should be at least 128 bits for AES encryption, 256 bits for elliptic-curve cryptography (ECC), and 2048 bits for RSA, DSA, or DH encryption. ExampleThe following code uses cryptographic algorithms with insufficient key sizes. KeyPairGenerator keyPairGen1 = KeyPairGenerator.getInstance("RSA");
keyPairGen1.initialize(1024); // BAD: Key size is less than 2048
KeyPairGenerator keyPairGen2 = KeyPairGenerator.getInstance("DSA");
keyPairGen2.initialize(1024); // BAD: Key size is less than 2048
KeyPairGenerator keyPairGen3 = KeyPairGenerator.getInstance("DH");
keyPairGen3.initialize(1024); // BAD: Key size is less than 2048
KeyPairGenerator keyPairGen4 = KeyPairGenerator.getInstance("EC");
ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp112r1"); // BAD: Key size is less than 256
keyPairGen4.initialize(ecSpec);
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(64); // BAD: Key size is less than 128To fix the code, change the key sizes to be the recommended size or larger for each algorithm. References
java/ql/src/Security/CWE/CWE-330/InsecureRandomness.qhelpInsecure randomnessIf you use a cryptographically weak pseudo-random number generator to generate security-sensitive values, such as passwords, attackers can more easily predict those values. Pseudo-random number generators generate a sequence of numbers that only approximates the properties of random numbers. The sequence is not truly random because it is completely determined by a relatively small set of initial values (the seed). If the random number generator is cryptographically weak, then this sequence may be easily predictable through outside observations. RecommendationThe Use a cryptographically secure pseudo-random number generator if the output is to be used in a security-sensitive context. As a general rule, a value should be considered "security-sensitive" if predicting it would allow the attacker to perform an action that they would otherwise be unable to perform. For example, if an attacker could predict the random password generated for a new user, they would be able to log in as that new user. ExampleThe following examples show different ways of generating a cookie with a random value. In the first (BAD) case, we generate a fresh cookie by appending a random integer to the end of a static string. The random number generator used ( Random r = new Random(); // BAD: Random is not cryptographically secure
byte[] bytes = new byte[16];
r.nextBytes(bytes);
String cookieValue = encode(bytes);
Cookie cookie = new Cookie("name", cookieValue);
response.addCookie(cookie);In the second (GOOD) case, we generate a fresh cookie by appending a random integer to the end of a static string. The random number generator used ( SecureRandom r = new SecureRandom(); // GOOD: SecureRandom is cryptographically secure
byte[] bytes = new byte[16];
r.nextBytes(bytes);
String cookieValue = encode(bytes);
Cookie cookie = new Cookie("name", cookieValue);
response.addCookie(cookie);References
java/ql/src/Security/CWE/CWE-501/TrustBoundaryViolation.qhelpTrust boundary violationA trust boundary violation occurs when a value is passed from a less trusted context to a more trusted context. For example, a value that is generated by a less trusted source, such as a user, may be passed to a more trusted source, such as a system process. If the less trusted source is malicious, then the value may be crafted to exploit the more trusted source. Trust boundary violations are often caused by a failure to validate input. For example, if a web application accepts a cookie from a user, then the application should validate the cookie before using it. If the cookie is not validated, then the user may be able to craft a malicious cookie that exploits the application. RecommendationTo maintain a trust boundary, validate data from less trusted sources before use. ExampleIn the first (bad) example, the server accepts a parameter from the user, then uses it to set the username without validation. public void doGet(HttpServletRequest request, HttpServletResponse response) {
String username = request.getParameter("username");
// BAD: The input is written to the session without being sanitized.
request.getSession().setAttribute("username", username);
}In the second (good) example, the server validates the parameter from the user, then uses it to set the username. public void doGet(HttpServletRequest request, HttpServletResponse response) {
String username = request.getParameter("username");
if (validator.isValidInput("HTTP parameter", username, "username", 20, false)) {
// GOOD: The input is sanitized before being written to the session.
request.getSession().setAttribute("username", username);
}
}References
java/ql/src/Violations of Best Practice/Comments/TodoComments.qhelpTODO/FIXME commentsA comment that includes the word For example, this list of comments is typical of those found in real programs:
RecommendationIt is very important that Simpler comments can usually be immediately addressed by fixing the code, adding a test, doing some refactoring, or clarifying the intended behavior of a feature. In contrast, larger issues may require discussion, and a significant amount of work to address. In these cases it is a good idea to move the comment to an issue-tracking system, so that the issue can be tracked and prioritized relative to other defects and feature requests. References
java/ql/src/Violations of Best Practice/Dead Code/DeadRefTypes.qhelpUnused classes and interfacesA non-public class or interface that is not used anywhere in the program may cause a programmer to waste time and effort maintaining and documenting it. RecommendationEnsure that redundant types are removed from the program. References
javascript/ql/src/Comments/TodoComments.qhelpTODO commentA comment that includes the words RecommendationAddress the problem indicated by the comment. ExampleIn the following example, the programmer has not yet implemented the correct behavior for the case where parameter function solveQuadratic(a, b, c) {
// TODO: handle case where a === 0
return (-b + Math.sqrt(b*b - 4*a*c))/(2*a);
}As a first step to fixing this problem, a check could be introduced that compares References
javascript/ql/src/Declarations/DeadStoreOfLocal.qhelpUseless assignment to local variableA value is assigned to a variable or property, but either that location is never read later on, or its value is always overwritten before being read. This means that the original assignment has no effect, and could indicate a logic error or incomplete code. RecommendationEnsure that you check the control and data flow in the method carefully. If a value is really not needed, consider omitting the assignment. Be careful, though: if the right-hand side has a side-effect (like performing a method call), it is important to keep this to preserve the overall behavior. ExampleIn the following example, the return value of the call to function f(x) {
var result = send(x);
waitForResponse();
return getResponse();
}Assuming that function f(x) {
var result = send(x);
// check for error
if (result === -1)
throw new Error("send failed");
waitForResponse();
return getResponse();
}References
javascript/ql/src/Declarations/DeadStoreOfProperty.qhelpUseless assignment to propertyA value is assigned to a variable or property, but either that location is never read later on, or its value is always overwritten before being read. This means that the original assignment has no effect, and could indicate a logic error or incomplete code. RecommendationEnsure that you check the control and data flow in the method carefully. If a value is really not needed, consider omitting the assignment. Be careful, though: if the right-hand side has a side-effect (like performing a method call), it is important to keep this to preserve the overall behavior. ExampleIn the following example, the return value of the call to function f(x) {
var result = send(x);
waitForResponse();
return getResponse();
}Assuming that function f(x) {
var result = send(x);
// check for error
if (result === -1)
throw new Error("send failed");
waitForResponse();
return getResponse();
}References
javascript/ql/src/LanguageFeatures/Eval.qhelpUse of evalThe built-in RecommendationThere are few genuine uses of ExampleIn the following example, function Point(x, y) {
this.x = x;
this.y = y;
}
["x", "y"].forEach(function(p) {
eval("Point.prototype.get_" + p + " = function() {" +
" return this." + p + ";" +
"}");
eval("Point.prototype.set_" + p + " = function(v) {" +
" if (typeof v !== 'number')" +
" throw Error('number expected');" +
" this." + p + " = v;" +
"}");
});In a variant, the programmer has realized that they can use computed property accesses to avoid having to wrap the assignment into an function Point(x, y) {
this.x = x;
this.y = y;
}
["x", "y"].forEach(function(p) {
Point.prototype["get_" + p] = new Function("",
"return this." + p + ";");
Point.prototype["set_" + p] = new Function("v",
"if (typeof v !== 'number')" +
" throw Error('number expected');" +
" this." + p + " = v;");
});This is not necessary either as the following example shows, where the use of function Point(x, y) {
this.x = x;
this.y = y;
}
["x", "y"].forEach(function(p) {
Point.prototype["get_" + p] = function() {
return this[p];
};
Point.prototype["set_" + p] = function(v) {
if (typeof v !== 'number')
throw Error('number expected');
this[p] = v;
};
});References
javascript/ql/src/Metrics/FCyclomaticComplexity.qhelpAverage cyclomatic complexity of filesThis metric measures the average cyclomatic complexity of the functions in a file. The cyclomatic complexity of a function is the number of linearly independent execution paths through that function. A path is linearly independent path if it differs from all other paths by at least one node. Straight-line code therefore has a cyclomatic complexity of one, while branches, switches and loops increase cyclomatic complexity. Functions with a high cyclomatic complexity are typically hard to understand and test. By extension, files whose functions have a high average cyclomatic complexity are problematic, and usually would benefit from refactoring. As a concrete example, consider the following function: function f(i, j) {
// start
var result;
if(i % 2 == 0) {
// iEven
result = i + j;
}
else {
// iOdd
if(j % 2 == 0) {
// jEven
result = i * j;
}
else {
// jOdd
result = i - j;
}
}
return result;
// end
}The control flow graph for this function is as follows:
RecommendationFunctions with a high cyclomatic complexity should be simplified, for instance by tidying up any complex logic within them or by splitting them into multiple methods using the Extract Method refactoring. References
javascript/ql/src/Metrics/FLinesOfDuplicatedCode.qhelpDuplicated lines in filesThis metric measures the number of lines in a file that are contained within a block that is duplicated elsewhere. These lines may include code, comments and whitespace, and the duplicate block may be in this file or in another file. A file that contains many lines that are duplicated within the code base is problematic for a number of reasons. Duplicated code increases overall code size, making the code base harder to maintain and harder to understand. It also becomes harder to fix bugs, since a programmer applying a fix to one copy has to always remember to update other copies accordingly. Finally, code duplication is generally an indication of a poorly designed or hastily written code base, which typically suffers from other problems as well. RecommendationRefactor files with lots of duplicated code to extract the common code into a shared library or module. References
javascript/ql/src/Metrics/FLinesOfSimilarCode.qhelpSimilar lines in filesThis metric measures the number of lines in a file that are contained within a block that is duplicated elsewhere. These lines may include code, comments and whitespace, and the duplicate block may be in this file or in another file. A file that contains many lines that are similar to other code within the code base is problematic for the same reasons as a file that contains a lot of (exactly) duplicated code. Duplicated code increases overall code size, making the code base harder to maintain and harder to understand. It also becomes harder to fix bugs, since a programmer applying a fix to one copy has to always remember to update other copies accordingly. Finally, code duplication is generally an indication of a poorly designed or hastily written code base, which typically suffers from other problems as well. RecommendationRefactor similar code snippets by extracting common functionality into functions that can be reused across modules. References
javascript/ql/src/Metrics/FunCyclomaticComplexity.qhelpCyclomatic complexity of functionsThis metric measures the cyclomatic complexity of each function in the project. The cyclomatic complexity of a function is an indication of the number of paths that can be taken during the execution of a function. Code with many branches and loops has high cyclomatic complexity. A cyclomatic complexity above 50 should be considered bad practice and above 75 should definitely be addressed. Functions with high cyclomatic complexity are
RecommendationThe primary way to reduce the complexity is to extract sub-functionality into separate functions. This improves on all problems described above. If the function naturally breaks up into a sequence of operations it is preferable to extract each operation as a separate function. Even if that's not the case it is often possible to extract the body of an iteration into a separate function to reduce complexity. If the complexity can't be reduced significantly make sure that the function is properly documented and carefully tested. References
javascript/ql/src/Security/CWE-079/ExceptionXss.qhelpException text reinterpreted as HTMLDirectly writing error messages to a webpage without sanitization allows for a cross-site scripting vulnerability if parts of the error message can be influenced by a user. RecommendationTo guard against cross-site scripting, consider using contextual output encoding/escaping before writing user input to the page, or one of the other solutions that are mentioned in the references. ExampleThe following example shows an exception being written directly to the document, and this exception can potentially be influenced by the page URL, leaving the website vulnerable to cross-site scripting. function setLanguageOptions() {
var href = document.location.href,
deflt = href.substring(href.indexOf("default=")+8);
try {
var parsed = unknownParseFunction(deflt);
} catch(e) {
document.write("Had an error: " + e + ".");
}
}ExampleThis second example shows an input being validated using the JSON schema validator import express from 'express';
import Ajv from 'ajv';
let app = express();
let ajv = new Ajv();
ajv.addSchema({type: 'object', additionalProperties: {type: 'number'}}, 'pollData');
app.post('/polldata', (req, res) => {
if (!ajv.validate('pollData', req.body)) {
res.send(ajv.errorsText());
}
});This is unsafe, because the error message can contain parts of the input. For example, the input References
javascript/ql/src/Security/CWE-079/ReflectedXss.qhelpReflected cross-site scriptingDirectly writing user input (for example, an HTTP request parameter) to an HTTP response without properly sanitizing the input first, allows for a cross-site scripting vulnerability. This kind of vulnerability is also called reflected cross-site scripting, to distinguish it from other types of cross-site scripting. RecommendationTo guard against cross-site scripting, consider using contextual output encoding/escaping before writing user input to the response, or one of the other solutions that are mentioned in the references. ExampleThe following example code writes part of an HTTP request (which is controlled by the user) directly to the response. This leaves the website vulnerable to cross-site scripting. var app = require('express')();
app.get('/user/:id', function(req, res) {
if (!isValidUserId(req.params.id))
// BAD: a request parameter is incorporated without validation into the response
res.send("Unknown user: " + req.params.id);
else
// TODO: do something exciting
;
});Sanitizing the user-controlled data prevents the vulnerability: var escape = require('escape-html');
var app = require('express')();
app.get('/user/:id', function(req, res) {
if (!isValidUserId(req.params.id))
// GOOD: request parameter is sanitized before incorporating it into the response
res.send("Unknown user: " + escape(req.params.id));
else
// TODO: do something exciting
;
});References
javascript/ql/src/Security/CWE-079/StoredXss.qhelpStored cross-site scriptingDirectly using uncontrolled stored value (for example, file names) to create HTML content without properly sanitizing the input first, allows for a cross-site scripting vulnerability. This kind of vulnerability is also called stored cross-site scripting, to distinguish it from other types of cross-site scripting. RecommendationTo guard against cross-site scripting, consider using contextual output encoding/escaping before using uncontrolled stored values to create HTML content, or one of the other solutions that are mentioned in the references. ExampleThe following example code writes file names directly to a HTTP response. This leaves the website vulnerable to cross-site scripting, if an attacker can choose the file names on the disk. var express = require('express'),
fs = require('fs');
express().get('/list-directory', function(req, res) {
fs.readdir('/public', function (error, fileNames) {
var list = '<ul>';
fileNames.forEach(fileName => {
// BAD: `fileName` can contain HTML elements
list += '<li>' + fileName + '</li>';
});
list += '</ul>'
res.send(list);
});
});Sanitizing the file names prevents the vulnerability: var express = require('express'),
fs = require('fs'),
escape = require('escape-html');
express().get('/list-directory', function(req, res) {
fs.readdir('/public', function (error, fileNames) {
var list = '<ul>';
fileNames.forEach(fileName => {
// GOOD: escaped `fileName` can not contain HTML elements
list += '<li>' + escape(fileName) + '</li>';
});
list += '</ul>'
res.send(list);
});
});References
javascript/ql/src/Security/CWE-079/UnsafeHtmlConstruction.qhelpUnsafe HTML constructed from library inputWhen a library function dynamically constructs HTML in a potentially unsafe way, then it's important to document to clients of the library that the function should only be used with trusted inputs. If the function is not documented as being potentially unsafe, then a client may inadvertently use inputs containing unsafe HTML fragments, and thereby leave the client vulnerable to cross-site scripting attacks. RecommendationDocument all library functions that can lead to cross-site scripting attacks, and guard against unsafe inputs where dynamic HTML construction is not intended. ExampleThe following example has a library function that renders a boldface name by writing to the module.exports = function showBoldName(name) {
document.getElementById('name').innerHTML = "<b>" + name + "</b>";
}This library function, however, does not escape unsafe HTML, and a client that calls the function with user-supplied input may be vulnerable to cross-site scripting attacks. The library could either document that this function should not be used with unsafe inputs, or use safe APIs such as module.exports = function showBoldName(name) {
const bold = document.createElement('b');
bold.innerText = name;
document.getElementById('name').appendChild(bold);
}Alternatively, an HTML sanitizer can be used to remove unsafe content. const striptags = require('striptags');
module.exports = function showBoldName(name) {
document.getElementById('name').innerHTML = "<b>" + striptags(name) + "</b>";
}References
javascript/ql/src/Security/CWE-079/UnsafeJQueryPlugin.qhelpUnsafe jQuery pluginLibrary plugins, such as those for the jQuery library, are often configurable through options provided by the clients of the plugin. Clients, however, do not know the implementation details of the plugin, so it is important to document the capabilities of each option. The documentation for the plugin options that the client is responsible for sanitizing is of particular importance. Otherwise, the plugin may write user input (for example, a URL query parameter) to a web page without properly sanitizing it first, which allows for a cross-site scripting vulnerability in the client application through dynamic HTML construction. RecommendationDocument all options that can lead to cross-site scripting attacks, and guard against unsafe inputs where dynamic HTML construction is not intended. ExampleThe following example shows a jQuery plugin that selects a DOM element, and copies its text content to another DOM element. The selection is performed by using the plugin option jQuery.fn.copyText = function(options) {
// BAD may evaluate `options.sourceSelector` as HTML
var source = jQuery(options.sourceSelector),
text = source.text();
jQuery(this).text(text);
}This is, however, not a safe plugin, since the call to Instead of documenting that the client is responsible for sanitizing jQuery.fn.copyText = function(options) {
// GOOD may not evaluate `options.sourceSelector` as HTML
var source = jQuery.find(options.sourceSelector),
text = source.text();
jQuery(this).text(text);
}References
javascript/ql/src/Security/CWE-079/Xss.qhelpClient-side cross-site scriptingDirectly writing user input (for example, a URL query parameter) to a webpage without properly sanitizing the input first, allows for a cross-site scripting vulnerability. This kind of vulnerability is also called DOM-based cross-site scripting, to distinguish it from other types of cross-site scripting. RecommendationTo guard against cross-site scripting, consider using contextual output encoding/escaping before writing user input to the page, or one of the other solutions that are mentioned in the references. ExampleThe following example shows part of the page URL being written directly to the document, leaving the website vulnerable to cross-site scripting. function setLanguageOptions() {
var href = document.location.href,
deflt = href.substring(href.indexOf("default=")+8);
document.write("<OPTION value=1>"+deflt+"</OPTION>");
document.write("<OPTION value=2>English</OPTION>");
}References
javascript/ql/src/Security/CWE-079/XssThroughDom.qhelpDOM text reinterpreted as HTMLExtracting text from a DOM node and interpreting it as HTML can lead to a cross-site scripting vulnerability. A webpage with this vulnerability reads text from the DOM, and afterwards adds the text as HTML to the DOM. Using text from the DOM as HTML effectively unescapes the text, and thereby invalidates any escaping done on the text. If an attacker is able to control the safe sanitized text, then this vulnerability can be exploited to perform a cross-site scripting attack. RecommendationTo guard against cross-site scripting, consider using contextual output encoding/escaping before writing text to the page, or one of the other solutions that are mentioned in the References section below. ExampleThe following example shows a webpage using a $("button").click(function () {
var target = $(this).attr("data-target");
$(target).hide();
});However, if an attacker can control the The above vulnerability can be fixed by using $("button").click(function () {
var target = $(this).attr("data-target");
$.find(target).hide();
});References
javascript/ql/src/Security/CWE-116/IncompleteHtmlAttributeSanitization.qhelpIncomplete HTML attribute sanitizationSanitizing untrusted input for HTML meta-characters is a common technique for preventing cross-site scripting attacks. Usually, this is done by escaping As a consequence, some programs only sanitize RecommendationSanitize all relevant HTML meta-characters when constructing HTML dynamically, and pay special attention to where the sanitized value is used. An even safer alternative is to design the application so that sanitization is not needed, for instance by using HTML templates that are explicit about the values they treat as HTML. ExampleThe following example code writes part of an HTTP request (which is controlled by the user) to an HTML attribute of the server response. The user-controlled value is, however, not sanitized for var app = require('express')();
app.get('/user/:id', function(req, res) {
let id = req.params.id;
id = id.replace(/<|>/g, ""); // BAD
let userHtml = `<div data-id="${id}">${getUserName(id) || "Unknown name"}</div>`;
// ...
res.send(prefix + userHtml + suffix);
});Sanitizing the user-controlled data for var app = require('express')();
app.get('/user/:id', function(req, res) {
let id = req.params.id;
id = id.replace(/<|>|&|"/g, ""); // GOOD
let userHtml = `<div data-id="${id}">${getUserName(id) || "Unknown name"}</div>`;
// ...
res.send(prefix + userHtml + suffix);
});References
javascript/ql/src/Security/CWE-116/UnsafeHtmlExpansion.qhelpUnsafe expansion of self-closing HTML tagSanitizing untrusted input for HTML meta-characters is a common technique for preventing cross-site scripting attacks. But even a sanitized input can be dangerous to use if it is modified further before a browser treats it as HTML. A seemingly innocent transformation that expands a self-closing HTML tag from RecommendationUse a well-tested sanitization library if at all possible, and avoid modifying sanitized values further before treating them as HTML. An even safer alternative is to design the application so that sanitization is not needed, for instance by using HTML templates that are explicit about the values they treat as HTML. ExampleThe following function transforms a self-closing HTML tag to a pair of open/close tags. It does so for all non- function expandSelfClosingTags(html) {
var rxhtmlTag = /<(?!img|area)(([a-z][^\w\/>]*)[^>]*)\/>/gi;
return html.replace(rxhtmlTag, "<$1></$2>"); // BAD
}While it is generally known regular expressions are ill-suited for parsing HTML, variants of this particular transformation pattern have long been considered safe. However, the function is not safe. As an example, consider the following string: <div alt="
<x" title="/>
<img src=url404 onerror=alert(1)>"/>When the above function transforms the string, it becomes a string that results in an alert when a browser treats it as HTML. <div alt="
<x" title="></x" >
<img src=url404 onerror=alert(1)>"/>References
javascript/ql/src/Security/CWE-338/InsecureRandomness.qhelpInsecure randomnessUsing a cryptographically weak pseudo-random number generator to generate a security-sensitive value, such as a password, makes it easier for an attacker to predict the value. Pseudo-random number generators generate a sequence of numbers that only approximates the properties of random numbers. The sequence is not truly random because it is completely determined by a relatively small set of initial values, the seed. If the random number generator is cryptographically weak, then this sequence may be easily predictable through outside observations. RecommendationUse a cryptographically secure pseudo-random number generator if the output is to be used in a security-sensitive context. As a rule of thumb, a value should be considered "security-sensitive" if predicting it would allow the attacker to perform an action that they would otherwise be unable to perform. For example, if an attacker could predict the random password generated for a new user, they would be able to log in as that new user. For JavaScript on the NodeJS platform, For JavaScript in the browser, ExampleThe following examples show different ways of generating a password. In the first case, we generate a fresh password by appending a random integer to the end of a static string. The random number generator used ( function insecurePassword() {
// BAD: the random suffix is not cryptographically secure
var suffix = Math.random();
var password = "myPassword" + suffix;
return password;
}In the second example, a cryptographically secure random number generator is used for the same purpose. In this case, it is much harder to predict the generated integers. function securePassword() {
// GOOD: the random suffix is cryptographically secure
var suffix = window.crypto.getRandomValues(new Uint32Array(1))[0];
var password = "myPassword" + suffix;
// GOOD: if a random value between 0 and 1 is desired
var secret = window.crypto.getRandomValues(new Uint32Array(1))[0] * Math.pow(2,-32);
}References
javascript/ql/src/Statements/DanglingElse.qhelpMisleading indentation of dangling 'else'In JavaScript, an Indenting the RecommendationEnsure that matching ExampleIn the following example, the function f() {
if (cond1())
if (cond2())
return 23;
else
return 42;
return 56;
}To correct this issue, indent the function f() {
if (cond1())
if (cond2())
return 23;
else
return 42;
return 56;
}Confusion about which function f() {
if (cond1()) {
if (cond2()) {
return 23;
} else {
return 42;
}
}
return 56;
}References
javascript/ql/src/Statements/UnreachableStatement.qhelpUnreachable statementAn unreachable statement almost always indicates missing code or a latent bug and should be examined carefully. RecommendationExamine the surrounding code to determine why the statement has become unreachable. If it is no longer needed, remove the statement. ExampleIn the following example, a spurious semicolon after the function f() {
if (someCond());
return 23;
return 42;
}To correct this issue, remove the spurious semicolon: function f() {
if (someCond())
return 23;
return 42;
}References
javascript/ql/src/experimental/heuristics/ql/src/Security/CWE-079/Xss.qhelpClient-side cross-site scripting with additional heuristic sourcesDirectly writing user input (for example, a URL query parameter) to a webpage without properly sanitizing the input first, allows for a cross-site scripting vulnerability. This kind of vulnerability is also called DOM-based cross-site scripting, to distinguish it from other types of cross-site scripting. RecommendationTo guard against cross-site scripting, consider using contextual output encoding/escaping before writing user input to the page, or one of the other solutions that are mentioned in the references. ExampleThe following example shows part of the page URL being written directly to the document, leaving the website vulnerable to cross-site scripting. function setLanguageOptions() {
var href = document.location.href,
deflt = href.substring(href.indexOf("default=")+8);
document.write("<OPTION value=1>"+deflt+"</OPTION>");
document.write("<OPTION value=2>English</OPTION>");
}References
python/ql/src/Metrics/FLinesOfDuplicatedCode.qhelpDuplicated lines in filesThis metric measures the number of lines in a file that are contained within a block that is duplicated elsewhere. These lines may include code, comments and whitespace, and the duplicate block may be in this file or in another file. A file that contains many lines that are duplicated within the code base is problematic for a number of reasons. Duplicated code increases overall code size, making the code base harder to maintain and harder to understand. It also becomes harder to fix bugs, since a programmer applying a fix to one copy has to always remember to update other copies accordingly. Finally, code duplication is generally an indication of a poorly designed or hastily written code base, which typically suffers from other problems as well. RecommendationRefactor files with lots of duplicated code to extract the common code into a shared library or module. References
ruby/ql/src/experimental/insecure-randomness/InsecureRandomness.qhelpInsecure randomnessUsing a cryptographically weak pseudo-random number generator to generate a security-sensitive value, such as a password, makes it easier for an attacker to predict the value. Pseudo-random number generators generate a sequence of numbers that only approximates the properties of random numbers. The sequence is not truly random because it is completely determined by a relatively small set of initial values, the seed. If the random number generator is cryptographically weak, then this sequence may be easily predictable through outside observations. RecommendationWhen generating values for use in security-sensitive contexts, it's essential to utilize a cryptographically secure pseudo-random number generator. As a general guideline, a value should be deemed "security-sensitive" if its predictability would empower an attacker to perform actions that would otherwise be beyond their reach. For instance, if an attacker could predict a newly generated user's random password, they would gain unauthorized access to that user's account. For Ruby, ExampleThe following examples show different ways of generating a password. The first example uses def generate_password()
chars = ('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a + ['!', '@', '#', '$', '%']
# BAD: rand is not cryptographically secure
password = (1..10).collect { chars[rand(chars.size)] }.join
end
password = generate_passwordIn the second example, the password is generated using require 'securerandom'
def generate_password()
chars = ('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a + ['!', '@', '#', '$', '%']
# GOOD: SecureRandom is cryptographically secure
password = SecureRandom.random_bytes(10).each_byte.map do |byte|
chars[byte % chars.length]
end.join
end
password = generate_password()References
ruby/ql/src/queries/security/cwe-079/ReflectedXSS.qhelpReflected server-side cross-site scriptingDirectly writing user input (for example, an HTTP request parameter) to a webpage, without properly sanitizing the input first, allows for a cross-site scripting vulnerability. RecommendationTo guard against cross-site scripting, escape user input before writing it to the page. Some frameworks, such as Rails, perform this escaping implicitly and by default. Take care when using methods such as ExampleThe following example is safe because the However, the following example is unsafe because user-controlled input is emitted without escaping, since it is marked as References
ruby/ql/src/queries/security/cwe-079/StoredXSS.qhelpStored cross-site scriptingDirectly writing an uncontrolled stored value (for example, a database field) to a webpage, without properly sanitizing the value first, allows for a cross-site scripting vulnerability. This kind of vulnerability is also called stored cross-site scripting, to distinguish it from other types of cross-site scripting. RecommendationTo guard against stored cross-site scripting, consider escaping before using uncontrolled stored values to create HTML content. Some frameworks, such as Rails, perform this escaping implicitly and by default. Take care when using methods such as ExampleThe following example is safe because the However, the following example may be unsafe because In the next example, content from a file on disk is inserted literally into HTML content. This approach is sometimes used to load script content, such as extensions for a web application, from files on disk. Care should taken in these cases to ensure both that the loaded files are trusted, and that the file cannot be modified by untrusted users. References
ruby/ql/src/queries/security/cwe-079/UnsafeHtmlConstruction.qhelpUnsafe HTML constructed from library inputWhen a library function dynamically constructs HTML in a potentially unsafe way, then it's important to document to clients of the library that the function should only be used with trusted inputs. If the function is not documented as being potentially unsafe, then a client may inadvertently use inputs containing unsafe HTML fragments, and thereby leave the client vulnerable to cross-site scripting attacks. RecommendationDocument all library functions that can lead to cross-site scripting attacks, and guard against unsafe inputs where dynamic HTML construction is not intended. ExampleThe following example has a library function that renders a boldface name by creating a string containing a class UsersController < ActionController::Base
# BAD - create a user description, where the name is not escaped
def create_user_description (name)
"<b>#{name}</b>".html_safe
end
endThis library function, however, does not escape unsafe HTML, and a client that calls the function with user-supplied input may be vulnerable to cross-site scripting attacks. The library could either document that this function should not be used with unsafe inputs, or escape the input before embedding it in the HTML fragment. class UsersController < ActionController::Base
# Good - create a user description, where the name is escaped
def create_user_description (name)
"<b>#{ERB::Util.html_escape(name)}</b>".html_safe
end
endReferences
ruby/ql/src/queries/variables/DeadStoreOfLocal.qhelpUseless assignment to local variableA value is assigned to a local variable, but either that variable is never read later on, or its value is always overwritten before being read. This means that the original assignment has no effect, and could indicate a logic error or incomplete code. RecommendationEnsure that you check the control and data flow in the method carefully. If a value is really not needed, consider omitting the assignment. Be careful, though: if the right-hand side has a side-effect (like performing a method call), it is important to keep this to preserve the overall behavior. ExampleIn the following example, the return value of the call to def f(x)
result = send(x)
waitForResponse
return getResponse
endAssuming that def f(x)
result = send(x)
# check for error
if (result == -1)
raise "Unable to send, check network."
end
waitForResponse
return getResponse
endReferences
|



Update 98 Wikipedia and Wikibooks references in non-Python query-help files from HTTP to HTTPS.
This is a scheme-only change: paths, fragments, and link text remain unchanged. The Python query-help subset is intentionally excluded because another contributor has already announced work on those links in #5163.
Validation:
git diff --checkPart of #5163.