MNT-21118: quickshare xss prevention (#536)

* MNT-21118: quickshare xss prevention

The selected way to prevent from xss attacks is forcing browsers to download files by adding Content-Disposition to the response headers as it is done in V1.

Forcing browsers to download files will always be the true for QuickShareContentGet, 
QuickShareThumbnailContentGet extends QuickShareContentGet, therefore the attach value will be overridden according to the url parameter "a".

In the test, the thumbnail must be generated by a logged in user before sharing the link to the document.
This commit is contained in:
Oussama Messeguem
2020-02-28 09:58:35 +00:00
committed by GitHub
parent f34faec4b3
commit 2b3003a84f
3 changed files with 85 additions and 60 deletions

View File

@@ -1,28 +1,28 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts.quickshare;
import java.io.IOException;
@@ -135,8 +135,11 @@ public class QuickShareContentGet extends ContentGet implements ServletContextAw
{
throw new InvalidNodeRefException(nodeRef);
}
executeImpl(nodeRef, params, req, res, null);
// MNT-21118 (XSS prevention)
// Force the attachment in case of asking for the content file only
// (will be overridden for thumbnails)
executeImpl(nodeRef, params, req, res, null, true);
return null;
}
@@ -160,7 +163,7 @@ public class QuickShareContentGet extends ContentGet implements ServletContextAw
}
}
protected void executeImpl(NodeRef nodeRef, Map<String, String> templateVars, WebScriptRequest req, WebScriptResponse res, Map<String, Object> model) throws IOException
protected void executeImpl(NodeRef nodeRef, Map<String, String> templateVars, WebScriptRequest req, WebScriptResponse res, Map<String, Object> model, boolean attach) throws IOException
{
// render content
QName propertyQName = ContentModel.PROP_CONTENT;
@@ -177,10 +180,7 @@ public class QuickShareContentGet extends ContentGet implements ServletContextAw
propertyQName = QName.createQName(propertyName, namespaceService);
}
}
// determine attachment
boolean attach = Boolean.valueOf(req.getParameter("a"));
// Stream the content
streamContentLocal(req, res, nodeRef, attach, propertyQName, model);
}

View File

@@ -1,28 +1,28 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts.quickshare;
import java.io.IOException;
@@ -81,7 +81,7 @@ public class QuickShareThumbnailContentGet extends QuickShareContentGet
}
@Override
protected void executeImpl(NodeRef nodeRef, Map<String, String> templateVars, WebScriptRequest req, WebScriptResponse res, Map<String, Object> model) throws IOException
protected void executeImpl(NodeRef nodeRef, Map<String, String> templateVars, WebScriptRequest req, WebScriptResponse res, Map<String, Object> model, boolean attach) throws IOException
{
String thumbnailName = templateVars.get("thumbnailname");
if (thumbnailName == null)
@@ -187,8 +187,11 @@ public class QuickShareThumbnailContentGet extends QuickShareContentGet
}
}
}
// determine attachment
attach = Boolean.valueOf(req.getParameter("a"));
super.executeImpl(thumbnailNodeRef, templateVars, req, res, model);
super.executeImpl(thumbnailNodeRef, templateVars, req, res, model, attach);
if (logger.isDebugEnabled())
{

View File

@@ -108,7 +108,7 @@ public class QuickShareRestApiTest extends BaseWebScriptTest
private final static String TEST_MIMETYPE_JPEG = MimetypeMap.MIMETYPE_IMAGE_JPEG;
private final static String TEST_MIMETYPE_PNG = MimetypeMap.MIMETYPE_IMAGE_PNG;
private static File quickFile = null;
private MutableAuthenticationService authenticationService;
private AuthenticationComponent authenticationComponent;
private NodeService nodeService;
@@ -357,6 +357,28 @@ public class QuickShareRestApiTest extends BaseWebScriptTest
assertFalse(nodeService.hasAspect(copyNodeRef, QuickShareModel.ASPECT_QSHARE));
}
public void testContentDispositionInResponseHeader() throws IOException, JSONException
{
checkTransformer();
String testNodeRef_3 = testNode.toString().replace("://", "/");
// Thumbnail creation by user one to genuinely create the thumbnail and allow the sharedId to get it
sendRequest(new GetRequest(AUTH_CONTENT_THUMBNAIL_URL.replace("{node_ref_3}", testNodeRef_3).replace("{thumbnailname}", "doclib")), 200, USER_ONE);
Response rsp = sendRequest(new PostRequest(SHARE_URL.replace("{node_ref_3}", testNodeRef_3), "", APPLICATION_JSON), 200, USER_ONE);
JSONObject jsonRsp = new JSONObject(new JSONTokener(rsp.getContentAsString()));
String sharedId = jsonRsp.getString("sharedId");
// In case of requesting the content only, Content-Disposition should be present to force browsers to download the file
rsp = sendRequest(new GetRequest(SHARE_CONTENT_URL.replace("{shared_id}", sharedId)), 200, USER_TWO);
assertNotNull("The response should contain a Content-Disposition entry in the header", rsp.getHeader("Content-Disposition"));
// In case of requesting the thumbnail, Content-Disposition should not be present
rsp = sendRequest(new GetRequest(SHARE_CONTENT_THUMBNAIL_URL.replace("{shared_id}", sharedId).replace("{thumbnailname}", "doclib")), 200, USER_TWO);
assertNull("The response should not contain a Content-Disposition entry in the header", rsp.getHeader("Content-Disposition"));
}
private void createUser(String userName)
{