nginx 에 lua 스 크 립 트 통합: 사용자 정의 Http 헤드 추가, IP 차단 등

11766 단어 nginxluaCSRF
Lua 는 Nginx 프로필 에 삽입 할 수 있 는 동적 스 크 립 트 언어 로 Nginx 가 요청 한 모든 단계 에서 다양한 Lua 코드 를 실행 할 수 있 습 니 다.처음에 우 리 는 Lua 로 요청 경 로 를 백 엔 드 서버 로 옮 겼 을 뿐 이지 만 구조 에 대한 역할 은 우리 의 기대 이상 이 었 다.다음은 우리 가 한 일 을 이야기 하 겠 습 니 다.
강제 검색엔진 은 mixlr. com 만 색인 합 니 다.
Google 은 하위 도 메 인 이름 을 완전히 독립 된 사이트 로 간주 합 니 다. 우 리 는 파충류 가 하위 도 메 인 이름 의 페이지 를 잡 아 페이지 rank 을 낮 추 는 것 을 원 하지 않 습 니 다.
location /{
  header_filter_by_lua '
    if ngx.var.query_string and ngx.re.match( ngx.var.query_string, "^([0-9]{10})$" ) then
      ngx.header["Expires"] = ngx.http_time( ngx.time() + 31536000 );
      ngx.header["Cache-Control"] = "max-age=31536000";
    end
  ';

robots. txt 에 대한 요청 이 mixlr. com 도 메 인 이 아니라면 내부 에 robots 로 다시 쓰기diallow. txt, 표준 재 작성 명령 도 이 수 요 를 실현 할 수 있 지만 Lua 의 실현 은 더욱 쉽게 이해 하고 유지 할 수 있 습 니 다.
프로그램 논리 에 따라 응답 헤드 설정
Lua 는 Nginx 기본 설정 규칙 보다 유연 한 설정 방식 을 제공 합 니 다.아래 의 예 에서 저 희 는 응답 헤드 를 정확하게 설정 해 야 합 니 다. 그러면 브 라 우 저가 지정 한 요청 헤드 를 보 낸 후에 무기한 캐 시 정적 파일 을 사용 할 수 있 습 니 다. 예, 사용 자 는 한 번 만 다운로드 하면 됩 니 다.이 재 작성 규칙 은 모든 정적 파일 을 만 듭 니 다. 요청 한 매개 변수 에 시간 스탬프 값 이 포함 되 어 있 으 면 Expires 와 Cache - Control 응답 헤드 를 설정 합 니 다.
location /{
  header_filter_by_lua '
    if ngx.var.query_string and ngx.re.match( ngx.var.query_string, "^([0-9]{10})$" ) then
      ngx.header["Expires"] = ngx.http_time( ngx.time() + 31536000 );
      ngx.header["Cache-Control"] = "max-age=31536000";
    end
  ';

  try_files $uri @dynamic;}

jQuery JSONP 에서 요청 한 타임 스탬프 인자 삭제
많은 외부 클 라 이언 트 가 JSONP 인 터 페 이 스 를 요청 할 때 타임 스탬프 와 유사 한 인 자 를 포함 하여 Nginx proxy 캐 시 를 명중 시 킬 수 없습니다 (지정 한 HTTP 인 자 를 무시 할 수 없 기 때 문 입 니 다).다음 규칙 은 시간 스탬프 인 자 를 삭제 하여 Nginx 가 upstream server 의 응답 내용 을 캐 시 하여 백 엔 드 서버 의 부 하 를 줄 일 수 있 도록 합 니 다.
location /{
  rewrite_by_lua '
    if ngx.var.args ~= nil then
      -- /some_request?_=1346491660 becomes /some_request
      local fixed_args, count = ngx.re.sub( ngx.var.args, "&?_=[0-9]+", "" );
      if count > 0 then
        return ngx.exec(ngx.var.uri, fixed_args);
      end
    end
  ';}

백 엔 드 의 느 린 요청 로 그 를 Nginx 의 오류 로그 에 기록 합 니 다.
백 엔 드 요청 응답 이 느 리 면 추가 추적 을 위해 Nginx 의 오류 로그 에 기록 할 수 있 습 니 다.
location /{
  log_by_lua '
    if tonumber(ngx.var.upstream_response_time) >= 1 then
      ngx.log(ngx.WARN, "[SLOW] Ngx upstream response time: " .. ngx.var.upstream_response_time .. "s from " .. ngx.var.upstream_addr);
    end
  ';}

Redis 기반 실시 간 IP 차단
어떤 경우 에는 불량배 파충류 의 포획 을 막 아야 한다. 이 는 전문 적 인 봉쇄 장 치 를 통 해 할 수 있 지만 루 아 를 통 해 간단 한 버 전의 봉쇄 를 실현 할 수 있다.
lua_shared_dict banned_ips 1m;

location /{
  access_by_lua '
    local banned_ips = ngx.shared.banned_ips;
    local updated_at = banned_ips:get("updated_at");

    -- only update banned_ips from Redis once every ten seconds:
    if updated_at == nil or updated_at < ( ngx.now() - 10 ) then
      local redis = require "resty.redis";
      local red = redis:new();
      red:set_timeout(200);

      local ok, err = red:connect("your-redis-hostname", 6379);
      if not ok then
        ngx.log(ngx.WARN, "Redis connection error retrieving banned_ips: " .. err);
      else
        local updated_banned_ips, err = red:smembers("banned_ips");
        if err then
          ngx.log(ngx.WARN, "Redis read error retrieving banned_ips: " .. err);
        else
          -- replace the locally stored banned_ips with the updated values:
          banned_ips:flush_all();
          for index, banned_ip in ipairs(updated_banned_ips) do
            banned_ips:set(banned_ip, true);
          end
          banned_ips:set("updated_at", ngx.now());
        end
      end
    end

    if banned_ips:get(ngx.var.remote_addr) then
      ngx.log(ngx.WARN, "Banned IP detected and refused access: " .. ngx.var.remote_addr);
      return ngx.exit(ngx.HTTP_FORBIDDEN);
    end
  ';}

현재 특정 IP 의 접근 을 막 을 수 있 습 니 다.
ruby> $redis.sadd("banned_ips","200.1.35.4")

Nginx 프로 세 스 는 10 초 마다 Redis 에서 최신 금지 IP 명단 을 가 져 옵 니 다.주의해 야 할 것 은 구조 에 Haproxy 와 같은 부하 균형 서버 를 사용 했다 면 $remoteaddr 는 정확 한 원 격 IP 주소 로 설정 합 니 다.
이 방법 은 HTTP User - agent 필드 의 검사 에 도 사용 할 수 있 으 며 지정 한 조건 을 만족 시 켜 야 합 니 다.
Nginx 출력 CSRF 사용 (form authenticity token)
Mixlr 는 페이지 캐 시 를 대량으로 사용 합 니 다. 이 를 통 해 각 페이지 에 세 션 단계 의 CSRF token 을 어떻게 출력 하 느 냐 가 문제 입 니 다.우 리 는 Nginx 의 하위 요청 을 통 해 upstream 웹 server 에서 token 을 가 져 온 다음 Nginx 의 SSI (server - side include) 기능 을 이용 하여 페이지 에 출력 합 니 다.이렇게 하면 CSRF 공격 문 제 를 해결 할 뿐만 아니 라 cache 가 정상적으로 이 용 될 수 있 도록 보장 한다.
location /csrf_token_endpoint {internal;

  include /opt/nginx/conf/proxy.conf;
  proxy_pass "http://upstream";}

location @dynamic{
  ssi on;set $csrf_token '';

  rewrite_by_lua '
    -- Using a subrequest, we our upstream servers for the CSRF token for this session:
    local csrf_capture = ngx.location.capture("/csrf_token_endpoint");
    if csrf_capture.status == 200 then
      ngx.var.csrf_token = csrf_capture.body;

      -- if this is a new session, ensure it sticks by passing through the new session_id
      -- to both the subsequent upstream request, and the response:
      if not ngx.var.cookie_session then
        local match = ngx.re.match(csrf_capture.header["Set-Cookie"], "session=([a-zA-Z0-9_+=/+]+);");
        if match then
          ngx.req.set_header("Cookie", "session=" .. match[1]);
          ngx.header["Set-Cookie"] = csrf_capture.header["Set-Cookie"];
        end
      end
    else
      ngx.log(ngx.WARN, "No CSRF token returned from upstream, ignoring.");
    end
  ';

  try_files /maintenance.html /rails_cache$uri @thin;}

CSRF 토 큰 생 성 app / metal / csrftoken_endpoint.rb:
classCsrfTokenEndpointdefself.call(env)if env["PATH_INFO"]=~/^\/csrf_token_endpoint/
      session = env["rack.session"]||{}

      token = session[:_csrf_token]if token.nil?
        token =SecureRandom.base64(32)
        session[:_csrf_token]= token
      end[200,{"Content-Type"=>"text/plain"},[ token ]]else[404,{"Content-Type"=>"text/html"},["Not Found"]]end
  endend

우리 의 모드 파일 예제:
<metaname=”csrf-param”value=”authenticity_token”/>
<meta name=”csrf-token” value=”<!–# echo var=”csrf_token” default=”” encoding=”none” –>”/>

Again you could make use of lua_shared_dict to store in memory the CSRF token for a particular session. This minimises the number of trips made to /csrf_token_endpoint.
원본 링크:http://devblog.mixlr.com/2012/09/01/nginx-lua/

좋은 웹페이지 즐겨찾기