Обратная косая черта "/" ломает вашу систему!

Java

Защита системы становится бумажным тигром

Обратите внимание, что во всех приведенных ниже примерах кода я опустил ненужный код и оставил только код ключа. Если вас больше интересуют детали кода, вы можете проверить соответствующий исходный код.

Я люблю делать некоторые отступления о программистах в конце статьи, чтобы помочь программистам расти, и вы можете посмотреть, если вам интересно.

Эта история начинается с уязвимости, обнаруженной компанией два дня назад.

Мы все знаем, что вам нужно войти в систему при просмотре веб-сайта. Дальнейшие операции могут быть выполнены только после получения соответствующей авторизации. например что-то вродеhttp://xxx/page/administratorЭтот интерфейс, в случае, если вы не вошли в систему, доступ вернет этот результат:

Недавно обнаруженная уязвимость относится к службам, развернутым на пристани. Уязвимость можно обойти, добавив обратную косую черту, т.е.http://xxx//page/administratorДанные могут быть возвращены в обычном режиме (из соображений безопасности обычные возвращаемые данные здесь не показаны),Аутентификация не требуется! ! !

Почему аутентификация обходится

Когда пристань соответствует фильтру,Используется относительно строгий шаблон соответствия,за/page/administratпуть, ударит/page/*, чтобы он перехватывался фильтром проверки подлинности (например, SSOFilter) для проверки подлинности.

Тем не мение,//page/administratЭтот вид пути с двумя обратными косыми чертами не относится к указанному выше правилу попадания, поэтому он не будет перехвачен, поэтому он будет въезжать прямо. Это ужасно! !

Решение

метод первый

Непосредственно установите правило сопоставления фильтра аутентификации на/*, заблокируйте любой доступ напрямую. Таким образом, нет возможности обойти, это настолько просто и грубо, что не нужно об этом беспокоиться.

Этот метод немного проблематичен, потому что мы знаем, что услуги в крупных компаниях обычно имеютмедицинское обследование. Система мониторинга получит доступ к пути проверки работоспособности и вернет код возврата http.200 OKДокажите, что сервис нормальный. Система мониторинга не будет предоставлять информацию об аутентификации при доступе к пути проверки работоспособности.

Поэтому приходится отдельно исключать путь проверки работоспособности в перехватчике, что очень некрасиво. Если путь проверки работоспособности не исключен, он всегда не будет возвращаться из-за сбоя аутентификации.200 OK, заставляя систему мониторинга думать, что ваша служба не работает, а затем выдавать предупреждение. Итак, есть метод два.

Способ второй

В обычном доступе его не будет//XXX/YYЭто своего рода незаконный запрос с несколькими обратными косыми чертами подряд. Итак, я добавляю перехватчик перед перехватчиком аутентификации, может ли этот перехватчик напрямую фильтровать такие незаконные запросы?

public void doFilter(ServletRequest request,ServletResponse response, FilterChain filterChain)
{
  String  url= request.getRequestURL();
  if(!url.indexOf("//")<0)
  { //很显然,公司代码里当然没有这么写,不过意思差不多
    response.getWriter().write("别跟爷爷闹,乖乖的输入地址")
  }else{
    ....
  }
}

response.getWriter().write("别跟爷爷闹,乖乖的输入地址")является сущностью.

** Ты сумасшедший, и ты сумасшедший, я прямо сломаю боевые искусства! **Логика проста, но работает. Пока ваш формат неправильный, вам вообще не будет предоставлен доступ. Если у вас есть какие-то трюки, просто используйте их, вы приходите, и я буду считать вас победителем!

Но вы можете спросить,url.indexOf("//")<0могу только судить//,Тот///или////Ждать этого? друг,///нет ни одного//Что ж? Он обязательно обнаружит тиоцианат!

Ты собираешься сорвать штаны?

Мы действительно решили указанную выше проблему, и риски безопасности были временно устранены.Но тщательно ли вы обдумывали вопрос?

Когда браузер брата-хакера увидит это предложение别跟爷爷闹,乖乖的输入地址, наша SSO действительно вступила в силу? Или,Его запрос на доступ был перехвачен нашим фильтром проверки формата после обхода SSOFilter. Или он сначала перехватывается фильтром проверки формата, а я вообще даже не трогал SSOFilter?

Между ними есть качественная разница.В первом случае он снял с вас штаны, но вы натянули их обратно со скоростью света. Последнее — когда ты застегиваешь ремень так, что он не может его стянуть, и дразнишь его саркастическими глазами. Хотя оба пока не рискуют выходить на улицу, очевидно, что у последнего максимальное чувство безопасности!

Итак, наша система первая или вторая? **Зависит от порядка загрузки фильтров в системе! **Чтобы говорить об этом вопросе, он принадлежит ребенку без матери, и это долгая история. Давайте сегодня подробнее рассмотрим этот вопрос.

Прошлое и настоящее фильтра

эффект

Фильтры в Интернете обычно называют фильтрами или перехватчиками. Вы можете почти узнать, что он делает, услышав имя.

По сути, фильтр очень похож на сервлет и может рассматриваться как еще одна особая форма сервлета. Как и сервлет, он также обрабатывает запрос, но фильтр не генерирует результат ответа, возвращаемый пользователю.

Фильтр играет ключевую роль в веб-приложениях, и фильтр должен выполнять многие функции. Например, общие: аутентификация, журналы доступа, кодирование и декодирование, перехват специальных запросов и т. д. могут быть реализованы через фильтры.

Конфигурация и примеры

Существует два способа настроить фильтр в веб-приложении: один — через web.xml, а другой — через аннотацию.

Ниже мы настраиваем Фильтр, который реализует простую функцию: когда есть доступ, наша консоль выводит有人访问啦Это предложение. В этом примере показаны две конфигурации по отдельности.

Определить фильтр

package quLunBianCheng;
public class DemoFilter implements Filter {

    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("容器启动时,会调用init方法对DemoFilter进行实例化哦");
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("有人来访问");
        chain.doFilter(request, response);
    }

    public void destroy() {
        System.out.println("DemoFilter要被销毁时,会先调用destroy方法");
    }
}


XML-конфигурация

<filter>
   <filter-name>DemoFilter</filter-name>
   <filter-class>quLunBianCheng.DemoFilter</filter-class>
 </filter>
 <filter-mapping>
    <filter-name>DemoFilter</filter-name>
    <url-pattern>/*</url-pattern>
 </filter-mapping>

Эта конфигурация должна быть нам знакома и всегда может быть найдена вweb.xmlсм. эту конфигурацию. <url-pattern>/*</url-pattern>означает, что весь доступ будетDemoFilterперехват. Поэтому всякий раз, когда есть доступ, у вас будет вывод на консоль.有人来访问啦

Отсюда можно вывести более сложные функции. Например, вы можете подсчитать количество посещений вашей веб-страницы, просто слегка изменив ее.DemoFilterМожно использовать метод doFilter.

public void doFilter(ServletRequest request,ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("有人来访问");
      	//访问次数+1	
      	Constant.visitCount++;
        System.out.println("你的网页已经被"+Constant.visitCount+"人访问过啦");  
        chain.doFilter(request, response);
    }
 

Аннотация @WebFilter

Форма аннотации имеет много преимуществ, таких как более удобный вид, более чистый код, отсутствие необходимости в файлах конфигурации xml и т.д. Однако по сути это то же самое, что и xml, просто другой способ.

Нет необходимости настраивать файл xml в методе аннотации, нужно только поставитьDemoFilterПросто внесите небольшое изменение.

package quLunBianCheng;
@WebFilter(filterName = "DemoFilter",urlPatterns = "/*")
public class DemoFilter implements Filter {

    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("容器启动时,会调用init方法对DemoFilter进行实例化哦");
    }
		//为了简洁起见,我这里吧dofilter和destory方法省略了,没有写出来。
}

просто добавь@WebFilter(filterName = "DemoFilter",urlPatterns = "/*")для завершения настройки.

По факту,@WebFilterСуществует множество необязательных параметров конфигурации для аннотаций, которые перечислены в конце статьи —>Дополнение к атрибутам @webFilter

Фильтры важны, но не бойтесь, это действительно так. Какие? Вы хотите знать процедуру инициализации фильтра? Эта следующая статья, эта статья не может быть написана. Поскольку внизу есть о чем поговорить, места не хватит.

Рождение фильтра аутентификации

Эта статья начинается с проблемы аутентификации, затем мы переходим к аутентификации. Фильтр, упомянутый ранее, должен вызывать фильтр аутентификации.

Фильтр аутентификации входа

По сути, фильтр аутентификации сам по себе является Фильтром, тут нет никакой загадки. Внедрите фильтр аутентификации за считанные минуты.

положить верхDemoFilterИзменив фильтр, он может стать браузером аутентификации входа.

package quLunBianCheng;
public class LoginFilter implements Filter {
    //省略非关键代码
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        //获得请求
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        //拿到cookie
        Cookie[] cookies = request.getCookies();
      	//遍历cookie,找到用户名和密码
      	String username = "";
        String password = "";
      	if (cookies != null && cookies.length > 0) {
            for (Cookie cookie : cookies) {
                if (cookie.getName().equals("username")) {
                    username = cookie.getValue();
                } else if (cookie.getName().equals("password")) {
                    password = cookie.getValue();
                }
            }
        }
      	//如果第一次登录没有cookie或者用户名、密码不一致,则让他重新登录
      	if (username.equals("") || password.equals("")||(!username.equals("XXX")) ||(!password.equals("XXXXXXX")) {
          	//重定向,让他登录
          	response.sendRedirect("login.jsp");	  
          	return ;
        } else{
          //如果通过就可以放行了  
          chain.doFilter(request,response);
        }
    }
}

в приведенном выше коде!username.equals("XXX")) ||(!password.equals("XXXXXXX")Это простая демонстрация, на самом деле в реальных проектах это запрашивается из базы данных, а неXXXXXX

Конфигурация фильтра здесь не детализирована, она такая же, как и предыдущая, вы можете использоватьweb.xmlили@webFilterАннотировать два способа настройки (но... пожалуйста, не используйте оба метода одновременно...)

Как видите, реализовать простой фильтр входа в систему очень просто. Но в реальной производственной среде он этого делать не будет, почему? Потому что это не безопасно! (**Младший программист-программист действительно усердно работает над безопасностью ваших данных, поэтому обещайте мне не устанавливать пароль наaaa123или123456789Это возможно? Встань на колени и поклонись онлайн!!!!**).

Не будем нести чушь, а разберемся, почему описанный выше подход небезопасен.Потому что мы храним имя пользователя и пароль непосредственно в файле cookie., файл cookie хранится в браузере пользователя и может быть легко взломан. Пользователям трудно иметь профессиональную способность защищать информацию о файлах cookie. Файл cookie, содержащий много важной личной информации (не только ваш пароль, но, возможно, и некоторую информацию о вас в физическом мире), представляет собой опасное поведение.

что делать? Если мы помещаем бессмысленный идентификационный код в файл cookie, вы приносите этот идентификационный код с каждым запросом, и сервер ищет информацию о пользователе (называемую сеансом), хранящуюся на сервере, с помощью идентификационного кода, и этот идентификационный код является идентификатором сеанса. Даже если хакер получит куки, он не сможет напрямую извлечь вашу личную информацию из куки, что намного безопаснее (в конце концов, способность сервера противостоять атакам намного сильнее, чем у пользовательской стороны. Если она должным образом защищена , хакер хочет получить ее с сервера.) Конфиденциальная информация намного сложнее).

Поэтому после некоторых изменений LoginFilter может стать следующимSSOFilter.

ssoFilter

package quLunBianCheng;
public class SsoFilter implements Filter {
    public void init(FilterConfig filterConfig) throws ServletException {
      /*初始化方法  接收一个FilterConfig类型的参数 该参数是对Filter的一些配置*/
    }
    public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {
       /*这里就不重复放代码了,用伪代码说一下把*/
        1:和上边一样,从Cookies中过滤出ssoId
        2:再拿着这个ssoId去服务器里查询出对应的登录名和密码
        3:如果登录名和密码匹配,就放行。如果不符合,就重新登录
    }
}

Таким образом, мы начинаем с уязвимости и полностью описываемFilter—>鉴权Filter->SSOFilter. И каждый шаг дает подробные примеры, даже включая информацию о конфигурации.

Но достаточно ли этого? НЕТ, все еще не совсем ОК. Я здесь! ! ! В одной статье я как-то сказал: «Технические люди должны научиться докапываться до сути вещей».

на шаг впереди

Этот раздел в основном знакомит с различными способами объявления, предлагает больше классов о фильтрах и пытается подробно объяснить их принципы.

Если не указано иное. SsoFilter, упомянутый в этом разделе, — это SsoFilter из предыдущего раздела.

Вы когда-нибудь видели такую ​​конфигурацию в web.xml?

<filter>
		<filter-name>SsoFilter</filter-name>
		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
		<init-param>
			<param-name>targetFilterLifecycle</param-name>
			<param-value>true</param-value>
		</init-param>
	</filter>
<filter-mapping>
    <filter-name>SsoFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Или такая конфигурация?

@Bean
public FilterRegistrationBean<Filter> LoginFilter() {
        FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new SsoFilter());
        registration.addUrlPatterns("/*");
        registration.setName("SsoFilter");
        registration.setOrder(0);
        registration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.FORWARD);
        return registration;
    }

Или такая конфигурация?

@Bean
public DelegatingFilterProxyRegistrationBean ssoFilterProxyRegistrationBean() {
    DelegatingFilterProxyRegistrationBean filterRegistration = new DelegatingFilterProxyRegistrationBean("ssoFilter");
    filterRegistration.addInitParameter("targetFilterLifecycle", "true");
    filterRegistration.addUrlPatterns("/*");
    filterRegistration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.FORWARD);
    filterRegistration.setOrder(2);
    return filterRegistration;
}

Есть большая вероятность, что вы это видели, но не обратили внимание или не обратили внимания, почему так написано. фактически,Функции, реализованные этими тремя методами, точно такие же, как у предыдущего ssoFilter, за исключением того, что используется прокси..

Я такой хороший, с чего мне вдруг идти к агенту? Потому что через прокси мы можем сделать наш собственный определенный ssoFilter идеально интегрированным с контейнером, пользоваться функцией контейнера spring и использовать spring для управления жизненным циклом фильтра.Если в фильтре используются некоторые bean-компоненты, их можно получить непосредственно инъекционным методом. ** Кроме того, есть много удобств. Поэтому нам необходимо понять эти прокси-методы.

Мы видим, что в этих трех направлениях появилось три новых прокси-класса.DelegatingFilterProxy,FilterRegistrationBeanиDelegatingFilterProxyRegistrationBean.

Я изначально хотел рассказать о последнем в этой статье, но мне показалось, что она слишком длинная, поэтому я планировал разделить ее на два выпуска.

В следующей статье мы поговорим о принципах этих трех классов прокси и ответим на вопросы, упомянутые выше.подобрать штаныПроблема.

приложение

медицинское обследование

Так называемая проверка здоровьяcontrollerЕсть интерфейс доступа, и общий путьxxx/alive. Получите доступ к этому пути, если возвращенный код ответа HTTP200, то у нас уже может быть запущена служба задач. Если вы не можете вернуться200, то теперь в системе должна быть проблема.

Дополнение к атрибутам @webFilter

Имя свойства тип описывать
filterName String Указывает атрибут имени фильтра
value String[] Это свойство эквивалентно свойству urlPatterns. Но оба не должны использоваться одновременно
urlPatterns String[] Задает шаблон сопоставления URL-адресов для набора фильтров. Эквивалент ярлыка
servletNames String[] Указывает, к каким сервлетам будет применяться фильтр. Значением является значение атрибута имени в @webServlet или значение в web.xml.
dispatcherTypers DispatcherType Указывает режим пересылки фильтра. Конкретные значения включают: ASYNC, ERROR, FORWARD, INCLUDE, REQUEST.
initParams WebInitParam[] Задает набор параметров инициализации фильтра, эквивалентных тегам
asyncSupported boolean Указывает, поддерживает ли фильтр асинхронный режим работы, эквивалентный метке
description String Описание фильтра, эквивалентное метке
displayName String Отображаемое имя фильтра, обычно используемое с инструментами, эквивалентно метке

На самом деле нам не нужно передавать какой-либо параметр аннотации.Байдуискать. Потому что для техника получение информации из первых рук — очень важная способность.

вы прямоcommand+鼠标左键Нажмите на аннотацию, и вы перейдете к определению соответствующей аннотации. @webFilter определяется следующим образом:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface WebFilter {

    String description() default "";
    
    String displayName() default "";
    
    WebInitParam[] initParams() default {};
    
    String filterName() default "";
    
    String smallIcon() default "";

    String largeIcon() default "";

    String[] servletNames() default {};
    
    String[] value() default {};

    String[] urlPatterns() default {};

    DispatcherType[] dispatcherTypes() default {DispatcherType.REQUEST};
    
    boolean asyncSupported() default false;
}

Наглядно видно какие параметры есть, и каждый четко и понятно прокомментирован.жить комфортно без чьей-либо помощи!

Цитаты

Цитировать:

Если человек не умеет плавать, он не может плавать ни в одном бассейне.

Разобрать:

Видите, некоторые программисты всегда жалуются, что у них мало шансов, что они поддерживают какой-то дерьмовый код, никаких проблем, только многословные и бессмысленные вещи. На самом деле нет ничего бессмысленного. Если вы можете посмотреть на проблему с другой точки зрения и столкнуться с некоторыми ситуациями с другим мышлением, у вас не будет этой жалобы.

Дайте любому хороший шанс, и результат не будет слишком плохим. Но те, кто действительно превосходят других, не выделяются судьбой. Те, кто жалуется на отсутствие возможностей, по-видимому, не хотят прилагать слишком много усилий и рассчитывают быстро разбогатеть. Гастарбайтеры, которые аккуратно строят стены на стройке, всегда ценятся прорабом. Делать что-либо до крайности не бессмысленно. Более того, люди, прочитавшие мою статью, находятся в лучшем положении и лучшем исходном положении, чем чернорабочие низшего звена.