К сожалению, размещение диалогов PrimeFaces Dialog Framework в /WEB-INF
, чтобы предотвратить прямой доступ, действительно не будет работать. Диалоги загружаются полностью на стороне клиента. По запросу POST, который открывает диалоговое окно, JSF / PrimeFaces возвращает сценарий oncomplete
с (общедоступным!) URL-адресом диалогового окна в JavaScript / jQuery, который, в свою очередь, показывает базовый шаблон диалогового окна с <iframe>
, URL-адрес которого установлен на URL-адрес диалогового окна. , который, в свою очередь, загружает контент. Фактически отправляются 2 запроса: первый для получения URL-адреса диалогового окна, а второй для получения содержимого диалогового окна на основе этого URL-адреса в <iframe>
.
Невозможно сохранить диалог в /WEB-INF
без возврата к «традиционному» подходу к диалогу через <p:dialog>
и условному отображению через JS / CSS. На стороне сервера также нет возможности проверить на основе некоторых заголовков, поступает ли запрос от <iframe>
, так что все остальные могут быть просто заблокированы. Ближайшая ваша ставка - это заголовок referer
, но его можно подделать.
Один из способов минимизировать злоупотребления - проверить наличие параметра запроса pfdlgcid
(обозначенного _ 10_) при запросе диалогового окна. PrimeFaces, в частности, добавляет этот параметр запроса, представляющий «идентификатор разговора», к URL-адресу диалога. Предполагая, что все диалоги хранятся в папке /dialogs
, вы можете выполнить эту работу с помощью простого фильтра сервлетов. Вот начальный пример, который отправляет ошибку HTTP 400, когда /dialogs/*
запрашивается без параметра запроса pfdlgcid
.
@WebFilter("/dialogs/*")
public class DialogFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String id = request.getParameter(Constants.DIALOG_FRAMEWORK.CONVERSATION_PARAM);
if (id != null) {
chain.doFilter(req, res); // Okay, just continue request.
}
else {
response.sendError(HttpServletResponse.SC_BAD_REQUEST); // 400 error.
}
}
// ...
}
Однако злоумышленник может быть не таким глупым и обнаружит параметр запроса pfdlgcid
во время обычного потока и все же сможет открыть диалоговое окно индивидуально при указании этого параметра, даже со случайным значением. Я подумал сравнить фактическое значение pfdlgcid
с известными. Я проверил исходный код PrimeFaces DialogNavigationHandler
, но, к сожалению, PrimeFaces не сохраняет это значение нигде в сеансе. Вам нужно будет предоставить пользовательскую реализацию DialogNavigationHandler
, в которой вы сохраняете значение pfdlgcid
в карте сеанса, которая, в свою очередь, также сравнивается в фильтре сервлета.
Сначала добавьте в DialogFilter
следующий метод:
public static Set<String> getIds(HttpServletRequest request) {
HttpSession session = request.getSession();
Set<String> ids = (Set<String>) session.getAttribute(getClass().getName());
if (ids == null) {
ids = new HashSet<>();
session.setAttribute(getClass().getName(), ids);
}
return ids;
}
Затем скопируйте PrimeFaces DialogNavigationHandler
исходный код в свой пакет и добавьте следующую строку после строки 62:
DialogFilter.getIds((HttpServletRequest) context.getExternalContext().getRequest()).add(pfdlgcid);
Замени <navigation-handler>
в faces-config.xml
на настроенный.
Наконец, измените условие if
в методе DialogFilter#doFilter()
следующим образом:
if (getIds(request).contains(id)) {
// ...
}
Теперь это предотвращает попытку злоумышленника открыть диалог со случайным идентификатором. Однако это не мешает злоумышленнику попытаться открыть диалоговое окно, скопировав точный <iframe>
URL-адрес сразу после его открытия. Учитывая то, как работает диалоговая структура PrimeFaces, предотвратить это невозможно. Вы можете в лучшем случае удалить значение pfdlgcid
из сеанса, когда диалог вот-вот вернется к родительскому. Однако, когда диалог закрывается чистыми средствами JS, это также игнорируется.
В общем, если вы действительно, действительно, не хотите, чтобы конечный пользователь мог открывать диалоговое окно индивидуально, тогда вы не можете обойти "традиционный" <p:dialog>
подход.
person
BalusC
schedule
27.07.2014