mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-14 17:58:59 +00:00
Merged HEAD-BUG-FIX (5.1/Cloud) to HEAD (5.1/Cloud)
98426: Merged 5.0.N (5.0.2) to HEAD-BUG-FIX (5.1/Cloud) 98384: Merged 5.0.1 (5.0.1) to 5.0.N (5.0.2) 98286: MNT-13473: Merged CLOUD39 (Cloud 39.3) to 5.0.1 (5.0.1) 97951: MNT-13456: git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@98533 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -1427,6 +1427,15 @@
|
||||
<property name="linksService" ref="LinksService"/>
|
||||
<property name="personService" ref="PersonService"/>
|
||||
<property name="activityService" ref="activityService"/>
|
||||
<property name="protocolsWhiteList"><value>${links.protocosl.white.list}</value></property>
|
||||
<property name="xssRegexp">
|
||||
<list>
|
||||
<value>.*s((\\*)|(\\[0]*)*)c((\\*)|(\\[0]*)*)r((\\*)|(\\[0]*)*)i((\\*)|(\\[0]*)*)p((\\*)|(\\[0]*)*)t((\\*)|(\\[0]*)*):.*</value>
|
||||
<value>.*on.*\(.*\).*=.*</value>
|
||||
<value><#{'$'}</value>
|
||||
<value>^<.*</value>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- Fetches the details of one link -->
|
||||
|
@@ -24,6 +24,7 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.alfresco.query.PagingRequest;
|
||||
import org.alfresco.repo.content.MimetypeMap;
|
||||
@@ -70,6 +71,10 @@ public abstract class AbstractLinksWebScript extends DeclarativeWebScript
|
||||
protected PersonService personService;
|
||||
protected ActivityService activityService;
|
||||
|
||||
private String protocolsWhiteList = "http,https,ftp,mailto";
|
||||
private ArrayList<String> allowedProtocols;
|
||||
private ArrayList<Pattern> xssPatterns;
|
||||
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
@@ -95,6 +100,98 @@ public abstract class AbstractLinksWebScript extends DeclarativeWebScript
|
||||
this.activityService = activityService;
|
||||
}
|
||||
|
||||
public void setProtocolsWhiteList(String protocolsWhiteList)
|
||||
{
|
||||
this.protocolsWhiteList = protocolsWhiteList;
|
||||
}
|
||||
|
||||
public void setXssRegexp(ArrayList<String> xssRegexp)
|
||||
{
|
||||
xssPatterns = new ArrayList<>(xssRegexp.size());
|
||||
for (String xssRegexpStr : xssRegexp)
|
||||
{
|
||||
xssPatterns.add(Pattern.compile(xssRegexpStr));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isProtocolAllowed(String protocol)
|
||||
{
|
||||
// will be used default protocol prefix
|
||||
if (protocol.length() == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (allowedProtocols == null)
|
||||
{
|
||||
allowedProtocols = new ArrayList<String>();
|
||||
for (String delimProtocol : protocolsWhiteList.split(","))
|
||||
{
|
||||
if (delimProtocol.trim().length() == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
allowedProtocols.add(delimProtocol.trim());
|
||||
}
|
||||
}
|
||||
|
||||
return allowedProtocols.contains(protocol);
|
||||
}
|
||||
|
||||
private boolean isPossibleXSS(String url)
|
||||
{
|
||||
// check for null
|
||||
if (xssPatterns == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean result = false;
|
||||
for (Pattern pattern : xssPatterns)
|
||||
{
|
||||
if (pattern.matcher(url).matches())
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean isUrlCorrect(String url)
|
||||
{
|
||||
//default behavior if url absent
|
||||
if (url == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (url.trim().length() == 0 || isPossibleXSS(url))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int colonPos = url.indexOf(":");
|
||||
colonPos = colonPos > 0 ? colonPos : 0;
|
||||
String protocol = url.substring(0, colonPos);
|
||||
|
||||
boolean result = isProtocolAllowed(protocol);
|
||||
//check for record host:port e.g.: localhost:8080
|
||||
if (!result)
|
||||
{
|
||||
String secondUrlPart = url.substring(colonPos+1);
|
||||
int slashPos = secondUrlPart.indexOf("/");
|
||||
slashPos = slashPos > 0 ? slashPos : secondUrlPart.length();
|
||||
String port = secondUrlPart.substring(0, slashPos);
|
||||
|
||||
Pattern p = Pattern.compile("^[0-9]*$");
|
||||
if (p.matcher(port).matches())
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
protected String getOrNull(JSONObject json, String key)
|
||||
{
|
||||
@@ -307,6 +404,17 @@ public abstract class AbstractLinksWebScript extends DeclarativeWebScript
|
||||
// Link name is optional
|
||||
String linkName = templateVars.get("path");
|
||||
|
||||
//sanitise url
|
||||
if (json != null)
|
||||
{
|
||||
String url = getOrNull(json, "url");
|
||||
if (!isUrlCorrect(url))
|
||||
{
|
||||
String error = "Url not allowed";
|
||||
throw new WebScriptException(Status.STATUS_BAD_REQUEST, error);
|
||||
}
|
||||
}
|
||||
|
||||
// Have the real work done
|
||||
return executeImpl(site, linkName, req, json, status, cache);
|
||||
}
|
||||
|
@@ -18,10 +18,12 @@
|
||||
*/
|
||||
package org.alfresco.repo.web.scripts.links;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.alfresco.repo.security.permissions.AccessDeniedException;
|
||||
import org.alfresco.service.cmr.links.LinkInfo;
|
||||
@@ -61,12 +63,13 @@ public class LinkPut extends AbstractLinksWebScript
|
||||
return model;
|
||||
}
|
||||
|
||||
|
||||
// Get the new link details from the JSON
|
||||
// Update the main properties
|
||||
link.setTitle(getOrNull(json, "title"));
|
||||
link.setDescription(getOrNull(json, "description"));
|
||||
link.setURL(getOrNull(json, "url"));
|
||||
String url = getOrNull(json, "url");
|
||||
|
||||
link.setURL(url);
|
||||
|
||||
// Handle internal / not internal
|
||||
if (json.containsKey("internal"))
|
||||
|
@@ -20,6 +20,7 @@ package org.alfresco.repo.web.scripts.links;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import javax.transaction.UserTransaction;
|
||||
@@ -539,6 +540,47 @@ public class LinksRestApiTest extends BaseWebScriptTest
|
||||
deleteLink(name, Status.STATUS_NOT_FOUND);
|
||||
}
|
||||
|
||||
/**
|
||||
* MNT-13456 Check for XSS attack via update of link
|
||||
* @throws Exception
|
||||
*/
|
||||
public void testXssLinks() throws Exception
|
||||
{
|
||||
String LINK_TITLE = "lnk" + System.currentTimeMillis();
|
||||
String LINK_URL = "http://alfresco.com";
|
||||
|
||||
HashMap<String, Integer> mapForCheck = new HashMap<String, Integer>();
|
||||
mapForCheck.put("http:javasc\\ript:alert('mail.ru')", Status.STATUS_BAD_REQUEST);
|
||||
mapForCheck.put("javas\\0cr\\ip\\00t:alert('dd')", Status.STATUS_BAD_REQUEST);
|
||||
mapForCheck.put("alfresco.my", Status.STATUS_OK);
|
||||
mapForCheck.put("javascript:alert('http://somedata.html')", Status.STATUS_BAD_REQUEST);
|
||||
mapForCheck.put("http://alfresco.org", Status.STATUS_OK);
|
||||
mapForCheck.put("localhost:8080", Status.STATUS_OK);
|
||||
mapForCheck.put("localhost:8080/share", Status.STATUS_OK);
|
||||
mapForCheck.put("localhost:80A80/share", Status.STATUS_BAD_REQUEST);
|
||||
mapForCheck.put("http:java\\00script:alert('XSS')", Status.STATUS_BAD_REQUEST);
|
||||
mapForCheck.put("http:javas\\0cript:alert('XSS')", Status.STATUS_BAD_REQUEST);
|
||||
mapForCheck.put("http:  javascript:alert('XSS')", Status.STATUS_BAD_REQUEST);
|
||||
mapForCheck.put("<SCRIPT/XSS SRC='http://ha.ckers.org/xss.js'></SCRIPT>", Status.STATUS_BAD_REQUEST);
|
||||
mapForCheck.put("<iframe src=http://ha.ckers.org/scriptlet.html <", Status.STATUS_BAD_REQUEST);
|
||||
mapForCheck.put("html:vbscript:msgbox(\"XSS\")", Status.STATUS_BAD_REQUEST);
|
||||
mapForCheck.put("<STYLE>@im\\port'\\ja\\vasc\\ript:alert(\"XSS\")';</STYLE>", Status.STATUS_BAD_REQUEST);
|
||||
mapForCheck.put("<IMG SRC= onmouseover=\"alert('xxs')\">", Status.STATUS_BAD_REQUEST);
|
||||
mapForCheck.put("BODY onload!#$%&()*~+-_.,:;?@[/|\\]^`=alert(\"XSS\")>", Status.STATUS_BAD_REQUEST);
|
||||
mapForCheck.put("onload54(dd)fg`=df", Status.STATUS_BAD_REQUEST);
|
||||
|
||||
JSONObject link;
|
||||
|
||||
link = createLink(LINK_TITLE, "Link desc", LINK_URL, false, Status.STATUS_OK);
|
||||
String name = getNameFromLink(link);
|
||||
|
||||
for (String url : mapForCheck.keySet())
|
||||
{
|
||||
int expStatus = mapForCheck.get(url);
|
||||
updateLink(name, LINK_TITLE, "Link desc", url, false, expStatus);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Listing
|
||||
*/
|
||||
|
Reference in New Issue
Block a user