Commits

Sebastian Sdorra committed 6138799 Merge

merge with branch issue-320

  • Participants
  • Parent commits b5f8ac8, cd535fe

Comments (0)

Files changed (3)

scm-core/src/main/java/sonia/scm/util/HttpUtil.java

 
 //~--- non-JDK imports --------------------------------------------------------
 
+import com.google.common.base.CharMatcher;
 import com.google.common.base.Strings;
 
 import org.slf4j.Logger;
 
   /**
    * Pattern for url normalization
-   * @sincee 1.26
+   * @since 1.26
    */
   private static final Pattern PATTERN_URLNORMALIZE =
     Pattern.compile("(?:(http://[^:]+):80(/.+)?|(https://[^:]+):443(/.+)?)");
+  
+  /**
+   * CharMatcher to select cr/lf and '%' characters
+   * @since 1.28
+   */
+  private static final CharMatcher CRLF_CHARMATCHER =
+    CharMatcher.anyOf("\n\r%");
 
   //~--- constructors ---------------------------------------------------------
 
   }
 
   /**
+   * Throws an {@link IllegalArgumentException} if the parameter contains
+   * illegal characters which could imply a CRLF injection attack.
+   * <stronng>Note:</strong> the current implementation throws the
+   * {@link IllegalArgumentException} also if the parameter contains a "%". So
+   * you have to decode your parameters before the check,
+   *
+   * @param parameter value
+   *
+   * @since 1.28
+   */
+  public static void checkForCRLFInjection(String parameter)
+  {
+    if (CRLF_CHARMATCHER.matchesAnyOf(parameter))
+    {
+      logger.error(
+        "parameter \"{}\" contains a character which could be an indicator for a crlf injection",
+        parameter);
+
+      throw new IllegalArgumentException(
+        "parameter contains an illegal character");
+    }
+  }
+
+  /**
    * Method description
    *
    *
   }
 
   /**
+   * Remove all chars from the given parameter, which could be used for
+   * CRLF injection attack. <stronng>Note:</strong> the current implementation
+   * the "%" char is also removed from the source parameter.
+   *
+   * @param parameter value
+   *
+   * @return the parameter value without crlf chars
+   *
+   * @since 1.28
+   */
+  public static String removeCRLFInjectionChars(String parameter)
+  {
+    return CRLF_CHARMATCHER.removeFrom(parameter);
+  }
+
+  /**
    * Method description
    *
    *

scm-core/src/test/java/sonia/scm/util/HttpUtilTest.java

       HttpUtil.normalizeUrl("http://www.scm-manager:8080"));
   }
 
+  /**
+   * Method description
+   *
+   */
+  @Test(expected = IllegalArgumentException.class)
+  public void testCheckForCRLFInjectionFailure1()
+  {
+    HttpUtil.checkForCRLFInjection("any%0D%0A");
+  }
+
+  /**
+   * Method description
+   *
+   */
+  @Test(expected = IllegalArgumentException.class)
+  public void testCheckForCRLFInjectionFailure2()
+  {
+    HttpUtil.checkForCRLFInjection("123\nabc");
+  }
+
+  /**
+   * Method description
+   *
+   */
+  @Test(expected = IllegalArgumentException.class)
+  public void testCheckForCRLFInjectionFailure3()
+  {
+    HttpUtil.checkForCRLFInjection("123\rabc");
+  }
+
+  /**
+   * Method description
+   *
+   */
+  @Test(expected = IllegalArgumentException.class)
+  public void testCheckForCRLFInjectionFailure4()
+  {
+    HttpUtil.checkForCRLFInjection("123\r\nabc");
+  }
+
+  /**
+   * Method description
+   *
+   */
+  @Test(expected = IllegalArgumentException.class)
+  public void testCheckForCRLFInjectionFailure5()
+  {
+    HttpUtil.checkForCRLFInjection("123%abc");
+  }
+
+  /**
+   * Method description
+   *
+   */
+  @Test
+  public void testCheckForCRLFInjectionSuccess()
+  {
+    HttpUtil.checkForCRLFInjection("123");
+    HttpUtil.checkForCRLFInjection("abc");
+    HttpUtil.checkForCRLFInjection("abcka");
+  }
+
+  /**
+   * Method description
+   *
+   */
+  @Test
+  public void testRemoveCRLFInjectionChars()
+  {
+    assertEquals("any0D0A", HttpUtil.removeCRLFInjectionChars("any%0D%0A"));
+    assertEquals("123abc", HttpUtil.removeCRLFInjectionChars("123\nabc"));
+    assertEquals("123abc", HttpUtil.removeCRLFInjectionChars("123\r\nabc"));
+    assertEquals("123abc", HttpUtil.removeCRLFInjectionChars("123%abc"));
+    assertEquals("123abc", HttpUtil.removeCRLFInjectionChars("123abc"));
+    assertEquals("123", HttpUtil.removeCRLFInjectionChars("123"));
+
+  }
+
   //~--- get methods ----------------------------------------------------------
 
   /**

scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryResource.java

 import sonia.scm.security.RepositoryPermission;
 import sonia.scm.security.ScmSecurityException;
 import sonia.scm.util.AssertUtil;
+import sonia.scm.util.HttpUtil;
 import sonia.scm.util.Util;
 
 //~--- JDK imports ------------------------------------------------------------
       {
         builder.setPath(path);
       }
+
       //J-
       builder.setDisableLastCommit(disableLastCommit)
              .setDisableSubRepositoryDetection(disableSubRepositoryDetection)
 
       output = new BrowserStreamingOutput(service, builder, path);
 
+     /**
+      * protection for crlf injection
+      * see https://bitbucket.org/sdorra/scm-manager/issue/320/crlf-injection-vulnerability-in-diff-api
+      */
+      path = HttpUtil.removeCRLFInjectionChars(path);
+      
       String contentDispositionName = getContentDispositionNameFromPath(path);
 
       response = Response.ok(output).header("Content-Disposition",
     AssertUtil.assertIsNotEmpty(id);
     AssertUtil.assertIsNotEmpty(revision);
 
+    /**
+     * check for a crlf injection attack
+     * see https://bitbucket.org/sdorra/scm-manager/issue/320/crlf-injection-vulnerability-in-diff-api
+     */
+    HttpUtil.checkForCRLFInjection(revision);
+
     RepositoryService service = null;
     Response response = null;