Merge pull request #18645 from fabienpe/main

Added missing "GOOD" and "BAD" to some examples
This commit is contained in:
Owen Mansel-Chan
2025-02-13 10:37:39 +00:00
committed by GitHub
41 changed files with 47 additions and 26 deletions

View File

@@ -4,6 +4,7 @@ public class SQLInjection extends HttpServlet {
StringBuilder sqlQueryBuilder = new StringBuilder();
sqlQueryBuilder.append("SELECT * FROM user WHERE user_id='");
// BAD: a request parameter is concatenated directly into a SQL query
sqlQueryBuilder.append(request.getParameter("user_id"));
sqlQueryBuilder.append("'");

View File

@@ -1,5 +1,6 @@
public class PartialPathTraversalBad {
public void example(File dir, File parent) throws IOException {
// BAD: dir.getCanonicalPath() not slash-terminated
if (!dir.getCanonicalPath().startsWith(parent.getCanonicalPath())) {
throw new IOException("Path traversal attempt: " + dir.getCanonicalPath());
}

View File

@@ -2,6 +2,7 @@ import java.io.File;
public class PartialPathTraversalGood {
public void example(File dir, File parent) throws IOException {
// GOOD: Check if dir.Path() is normalised
if (!dir.toPath().normalize().startsWith(parent.toPath())) {
throw new IOException("Path traversal attempt: " + dir.getCanonicalPath());
}

View File

@@ -20,4 +20,5 @@ webview.addJavaScriptInterface(new ExposedObject(), "exposedObject");
webview.loadData("", "text/html", null);
String name = "Robert'; DROP TABLE students; --";
// BAD: Untrusted input loaded into WebView
webview.loadUrl("javascript:alert(exposedObject.studentEmail(\""+ name +"\"))");

View File

@@ -1,2 +1,2 @@
WebSettings settings = webview.getSettings();
settings.setJavaScriptEnabled(false);
settings.setJavaScriptEnabled(false); // GOOD: webview has JavaScript disabled

View File

@@ -1,2 +1,2 @@
WebSettings settings = webview.getSettings();
settings.setJavaScriptEnabled(true);
settings.setJavaScriptEnabled(true); // BAD: webview has JavaScript enabled

View File

@@ -2,26 +2,26 @@ public class GroovyInjection {
void injectionViaClassLoader(HttpServletRequest request) {
String script = request.getParameter("script");
final GroovyClassLoader classLoader = new GroovyClassLoader();
Class groovy = classLoader.parseClass(script);
Class groovy = classLoader.parseClass(script); // BAD: Groovy code injection
GroovyObject groovyObj = (GroovyObject) groovy.newInstance();
}
void injectionViaEval(HttpServletRequest request) {
String script = request.getParameter("script");
Eval.me(script);
Eval.me(script); // BAD: Groovy code injection
}
void injectionViaGroovyShell(HttpServletRequest request) {
GroovyShell shell = new GroovyShell();
String script = request.getParameter("script");
shell.evaluate(script);
shell.evaluate(script); // BAD: Groovy code injection
}
void injectionViaGroovyShellGroovyCodeSource(HttpServletRequest request) {
GroovyShell shell = new GroovyShell();
String script = request.getParameter("script");
GroovyCodeSource gcs = new GroovyCodeSource(script, "test", "Test");
shell.evaluate(gcs);
shell.evaluate(gcs); // BAD: Groovy code injection
}
}

View File

@@ -9,6 +9,7 @@ import java.io.File;
File file = new File(Environment.getExternalStorageDirectory(), "myapp.apk");
Intent intent = new Intent(Intent.ACTION_VIEW);
/* Set the mimetype to APK */
// BAD: The file may be altered by another app
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
startActivity(intent);

View File

@@ -21,6 +21,7 @@ try (InputStream is = getAssets().open(assetName);
/* Expose temporary file with FileProvider */
File toInstall = new File(this.getFilesDir(), tempFilename);
// GOOD: The file is protected by FileProvider
Uri applicationUri = FileProvider.getUriForFile(this, "com.example.apkprovider", toInstall);
/* Create Intent and set data to APK file. */

View File

@@ -1,3 +1,4 @@
// GOOD: Package installed using PackageInstaller
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInstaller;

View File

@@ -14,6 +14,7 @@ public class VelocitySSTI {
StringWriter w = new StringWriter();
// evaluate( Context context, Writer out, String logTag, String instring )
// BAD: code is controlled by the user
Velocity.evaluate(context, w, "mystring", code);
}
}

View File

@@ -11,7 +11,7 @@ public class VelocitySSTI {
String s = "We are using $project $name to render this.";
StringWriter w = new StringWriter();
Velocity.evaluate(context, w, "mystring", s);
Velocity.evaluate(context, w, "mystring", s); // GOOD: s is a constant string
System.out.println(" string : " + w);
}
}

View File

@@ -4,7 +4,7 @@ public void evaluate(Socket socket) throws IOException {
JexlSandbox onlyMath = new JexlSandbox(false);
onlyMath.white("java.lang.Math");
JexlEngine jexl = new JexlBuilder().sandbox(onlyMath).create();
JexlEngine jexl = new JexlBuilder().sandbox(onlyMath).create(); // GOOD: using a sandbox
String input = reader.readLine();
JexlExpression expression = jexl.createExpression(input);

View File

@@ -6,7 +6,7 @@ public void evaluate(Socket socket) throws IOException {
JexlEngine jexl = new JexlBuilder().uberspect(sandbox).create();
String input = reader.readLine();
JexlExpression expression = jexl.createExpression(input);
JexlExpression expression = jexl.createExpression(input); // GOOD: jexl uses a sandbox
JexlContext context = new MapContext();
expression.evaluate(context);
}

View File

@@ -4,9 +4,11 @@ public Object evaluate(Socket socket) throws IOException {
String string = reader.readLine();
ExpressionParser parser = new SpelExpressionParser();
// AVOID: string is controlled by the user
Expression expression = parser.parseExpression(string);
SimpleEvaluationContext context
= SimpleEvaluationContext.forReadWriteDataBinding().build();
// OK: Untrusted expressions are evaluated in a restricted context
return expression.getValue(context);
}
}

View File

@@ -4,6 +4,7 @@ public void evaluate(Socket socket) throws IOException {
String input = reader.readLine();
JexlEngine jexl = new JexlBuilder().create();
// BAD: input is controlled by the user
JexlExpression expression = jexl.createExpression(input);
JexlContext context = new MapContext();
expression.evaluate(context);

View File

@@ -4,6 +4,7 @@ public Object evaluate(Socket socket) throws IOException {
String string = reader.readLine();
ExpressionParser parser = new SpelExpressionParser();
// BAD: string is controlled by the user
Expression expression = parser.parseExpression(string);
return expression.getValue();
}

View File

@@ -1,4 +1,4 @@
byte[] iv = new byte[16]; // all zeroes
byte[] iv = new byte[16]; // BAD: all zeroes
GCMParameterSpec params = new GCMParameterSpec(128, iv);
Cipher cipher = Cipher.getInstance("AES/GCM/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, key, params);

View File

@@ -1,6 +1,6 @@
byte[] iv = new byte[16];
SecureRandom random = SecureRandom.getInstanceStrong();
random.nextBytes(iv);
random.nextBytes(iv); // GOOD: random initialization vector
GCMParameterSpec params = new GCMParameterSpec(128, iv);
Cipher cipher = Cipher.getInstance("AES/GCM/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, key, params);

View File

@@ -1,2 +1,2 @@
TextView pwView = getViewById(R.id.pw_text);
pwView.setText("Your password is: " + password);
pwView.setText("Your password is: " + password); // BAD: password is shown immediately

View File

@@ -5,6 +5,6 @@ pwView.setText("Your password is: " + password);
Button showButton = findViewById(R.id.show_pw_button);
showButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
pwView.setVisibility(View.VISIBLE);
pwView.setVisibility(View.VISIBLE); // GOOD: password is only shown when the user clicks the button
}
});

View File

@@ -1,3 +1,4 @@
WebSettings settings = webview.getSettings();
// GOOD: WebView is configured to disallow content access
settings.setAllowContentAccess(false);

View File

@@ -1,3 +1,4 @@
WebSettings settings = webview.getSettings();
// BAD: WebView is configured to allow content access
settings.setAllowContentAccess(true);

View File

@@ -1,5 +1,6 @@
WebSettings settings = view.getSettings();
// GOOD: WebView is configured to disallow file access
settings.setAllowFileAccess(false);
settings.setAllowFileAccessFromURLs(false);
settings.setAllowUniversalAccessFromURLs(false);

View File

@@ -1,5 +1,6 @@
WebSettings settings = view.getSettings();
// BAD: WebView is configured to allow file access
settings.setAllowFileAccess(true);
settings.setAllowFileAccessFromURLs(true);
settings.setAllowUniversalAccessFromURLs(true);

View File

@@ -1,4 +1,4 @@
Random r = new Random();
Random r = new Random(); // BAD: Random is not cryptographically secure
byte[] bytes = new byte[16];
r.nextBytes(bytes);

View File

@@ -1,4 +1,4 @@
SecureRandom r = new SecureRandom();
SecureRandom r = new SecureRandom(); // GOOD: SecureRandom is cryptographically secure
byte[] bytes = new byte[16];
r.nextBytes(bytes);

View File

@@ -12,14 +12,14 @@ class Resource {
public synchronized void bad(Resource r) {
if (r.isReady()) {
// r might no longer be ready, another thread might
// BAD: r might no longer be ready, another thread might
// have called setReady(false)
r.act();
}
}
public synchronized void good(Resource r) {
synchronized(r) {
synchronized(r) { // GOOD: r is locked
if (r.isReady()) {
r.act();
}

View File

@@ -7,6 +7,6 @@ public MyObject {
public MyObject deserialize(Socket sock) {
try(ObjectInputStream in = new ObjectInputStream(sock.getInputStream())) {
return (MyObject)in.readObject(); // unsafe
return (MyObject)in.readObject(); // BAD: in is from untrusted source
}
}

View File

@@ -1,5 +1,5 @@
public MyObject deserialize(Socket sock) {
try(DataInputStream in = new DataInputStream(sock.getInputStream())) {
return new MyObject(in.readInt());
return new MyObject(in.readInt()); // GOOD: read only an int
}
}

View File

@@ -1,3 +1,4 @@
// BAD: LDAP authentication is used
String ldapUrl = "ldap://ad.your-server.com:389";
Hashtable<String, String> environment = new Hashtable<String, String>();
environment.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");

View File

@@ -1,3 +1,4 @@
// GOOD: LDAP connection using LDAPS
String ldapUrl = "ldaps://ad.your-server.com:636";
Hashtable<String, String> environment = new Hashtable<String, String>();
environment.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");

View File

@@ -1,3 +1,4 @@
// GOOD: LDAP is used but SASL authentication is enabled
String ldapUrl = "ldap://ad.your-server.com:389";
Hashtable<String, String> environment = new Hashtable<String, String>();
environment.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");

View File

@@ -1,5 +1,5 @@
public void parse(Socket sock) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
builder.parse(sock.getInputStream()); //unsafe
builder.parse(sock.getInputStream()); // BAD: DTD parsing is enabled
}

View File

@@ -2,5 +2,5 @@ public void disableDTDParse(Socket sock) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
DocumentBuilder builder = factory.newDocumentBuilder();
builder.parse(sock.getInputStream()); //safe
builder.parse(sock.getInputStream()); // GOOD: DTD parsing is disabled
}

View File

@@ -3,7 +3,7 @@ import com.amazonaws.auth.BasicAWSCredentials;
public class HardcodedAWSCredentials {
public static void main(String[] args) {
//Hardcoded credentials for connecting to AWS services
// BAD: Hardcoded credentials for connecting to AWS services
//To fix the problem, use other approaches including AWS credentials file, environment variables, or instance/container credentials instead
AWSCredentials creds = new BasicAWSCredentials("ACCESS_KEY", "SECRET_KEY"); //sensitive call
}

View File

@@ -1,8 +1,8 @@
private static final String p = "123456"; // hard-coded credential
private static final String p = "123456"; // BAD: hard-coded credential
public static void main(String[] args) throws SQLException {
String url = "jdbc:mysql://localhost/test";
String u = "admin"; // hard-coded credential
String u = "admin"; // BAD: hard-coded credential
getConn(url, u, p);
}

View File

@@ -1,5 +1,5 @@
for (int i=0; i<10; i++) {
for (int j=0; i<10; j++) {
for (int j=0; i<10; j++) { // BAD: Potential infinite loop: i should be j
// do stuff
if (shouldBreak()) break;
}

View File

@@ -1,5 +1,5 @@
for (int i=0; i<10; i++) {
for (int j=0; j<10; j++) {
for (int j=0; j<10; j++) { // GOOD: correct variable j
// do stuff
if (shouldBreak()) break;
}

View File

@@ -1,6 +1,7 @@
public class ShutdownReceiver extends BroadcastReceiver {
@Override
public void onReceive(final Context context, final Intent intent) {
// BAD: The code does not check if the intent is an ACTION_SHUTDOWN intent
mainActivity.saveLocalData();
mainActivity.stopActivity();
}

View File

@@ -1,6 +1,7 @@
public class ShutdownReceiver extends BroadcastReceiver {
@Override
public void onReceive(final Context context, final Intent intent) {
// GOOD: The code checks if the intent is an ACTION_SHUTDOWN intent
if (!intent.getAction().equals(Intent.ACTION_SHUTDOWN)) {
return;
}