redisを使用して、悪意のあるhttp要求攻撃に抵抗するための単純な防御モジュールを作成します
序文
私は初心者で、通常csdnを書く習慣はありません。小さなアウトソーシングプロジェクトを終えたばかりで、何も問題はありません。突然、気まぐれで大胆な考えが浮かびます。長年、2G + 1MのAlibabaCloudサーバーのパフォーマンスを信じることができなかったため、悪意のあるユーザーがブラウザーやプログラムを介してサーバーへのhttpアクセスを使用しないように、自分で簡単なHTTPセキュリティモジュールを構築しようと常に考えていました。空の状態で、新しく学習したredisを使用して、自分で開発した中古市場の元のスプリングブートプロジェクトに対する悪意のあるhttp攻撃を検出する予定です。現在、csdnでこの輝かしい瞬間を記録しています。記事の口述の一部として、コードを使用することに慣れています。 、そしてコードを大規模にコピーしないので、スプリングブーツの基礎が弱いと不快感を感じるかもしれません。ご容赦ください。
ヒント:以下はこの記事の内容です。以下のケースは参照用です
1.原則とアイデア
redisはメモリベースのキャッシュサーバーであるため、高いパフォーマンスと安定性を備え、市場のテストに耐えてきました。カスタムインターセプター、接続要求、およびredisは、各http要求ipへの最近のアクセス数を記録するために使用されます。異常な状況が見つかった場合(短時間に大量のリクエストを送信する)は、悪意のあるHTTPリクエスト攻撃と見なすことができます。IPをブロックすることができ、IPをログに記録することができます。
2.手順の手順
1.依存関係を導入し、redisを構成します
テストを容易にするために、仕事用のコンピューターを使用してspringbootプロジェクトをデバッグおよび実行し、redisサーバーはAlibabaCloud上に構築されています。
<!--redis 依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
#redis配置
spring.redis.host = ...
spring.redis.port = ... [默认6379]
spring.redis.password = [如果你的redis服务器有密码]
2.redisシリアライザーとRedisTemplateをカスタマイズします
タイプ<String、Integer>のRedisTemplateが必要であり、その値をjavaの整数として、およびredisの文字列として、手動で変換せずに柔軟に使用する必要があります。同時に、redisサーバーで保証できます。読みやすさ。springbootのredis統合apiは、ばかげたRedisTemplate <String、Integer>を提供します。Integerのシリアル化は明らかに要件を満たしていないため、RedisTemplateとシリアライザーをカスタマイズすることしかできません。私は1つを構築することに慣れています。 configパッケージ、パッケージクラスのbeanメソッドを使用して独自の設定Beanを作成します
2.1。シリアライザー
RedisSerializer <Integer>インターフェイスを実装し、そのシリアル化メソッドと逆シリアル化メソッドをオーバーライドするクラスを定義します
私たちの目的は、redisに文字列文字として格納し、javaに整数の形式で表示することであるため、実現のアイデアは非常に単純です。シリアル化するときは、整数を文字列に変換してからシリアル化し、シリアル化したものを逆シリアル化します。文字列を整数に変換する
@Override
public byte[] serialize(@Nullable Integer integer) throws SerializationException {
return integer== null ? null : integer.toString().getBytes(StandardCharsets.UTF_8);
}
@Override
public Integer deserialize(@Nullable byte[] bytes) throws SerializationException {
return bytes == null ? null : Integer.valueOf(new String(bytes,
StandardCharsets.UTF_8));
}
2.2.RedisTemplate
RedisTemplate <String、Integer>オブジェクトを作成し、そのキーに文字列シリアル化戦略を使用するだけです(シリアル化戦略が文字列オブジェクトを文字として使用しない愚かなjdkデフォルトシリアライザーを使用しないでください。バイト配列は保存され、古代の人間が使用する奇妙なシンボルにシリアル化されます)上記でカスタマイズしたシリアライザーの値が使用されるため、コア操作は次のようになります。
setKeySerializer(new StringRedisSerializer());
setValueSerializer(intRedisSerializer);
全体のコードは次のとおりです
@Configuration
public class RedisConfig {
@Autowired
RedisSerializer<Integer> intRedisSerializer;
@Bean("intRedisTemplate")
public RedisTemplate<String, Integer> IntRedisTemplate(RedisConnectionFactory rcf){
RedisTemplate<String, Integer> re = new RedisTemplate();
re.setConnectionFactory(rcf);
re.setKeySerializer(new StringRedisSerializer());
re.setValueSerializer(intRedisSerializer);
return re;
}
}
説明:私は、以前の整数シリアライザintRedisSerializer名前が付けられ、中にそれを注入しRedisTemplate
3.探偵クラスは、http攻撃を検出するコア機能を実装します
スマートに、フォントの色が暗くなっていることに気付いたかもしれません。これは、フォントの色を変更する方法がわからないためではありませんが、コアコードが開始されようとしています。!!
Detective(HttpDetective)という名前は10分近くかかりました。インターフェイスはinspection(String ip)メソッドを宣言して、このipがサーバーにアクセスできるかどうかを判断し、その機能を実装するためにHttpDetectiveImplを作成します。非同期によって引き起こされる可能性のある実際のパラメータエラーを無視する、シンプルでフォールトトレラントな戦略ですが、これは機能と安全性には影響しません。具体的なコードは次のとおりです。
@Component("httpDetective")
public class HttpDetectiveImpl implements HttpDetective {
@Autowired
private RedisTemplate<String, Integer> intRedisTemplate;
/**单位均为毫秒*/
private final int RECORD_TIME = 1000;
private final int ALLOW_TIMES = 6;
private final int REFUSE_TIME = 180000;
@Override
public boolean inspection(String ip) {
Integer times = intRedisTemplate.opsForValue().get(ip);
if(times == null){
System.out.println("有正常人进入");
intRedisTemplate.opsForValue().set(ip, 1, RECORD_TIME, TimeUnit.MILLISECONDS);
return true;
}else{
if(times >= ALLOW_TIMES){
System.out.println("认定为入侵行为 拦截访问 并且禁止目标短时间内再次访问并且记录 入侵者ip"+ ip);
intRedisTemplate.opsForValue().set(ip, ALLOW_TIMES, REFUSE_TIME, TimeUnit.MILLISECONDS);
return false;
}else{
System.out.println("有可疑人进入. "+times);
intRedisTemplate.opsForValue().increment(ip);
return true;
}
}
}
}
以前のRedisTemplateを、検出クラスのツールとして検出クラスに挿入します。その後の変更を容易にするために、3つの定数をすべてミリ秒単位で定義します。
RECORD_TIME:httpアクセスの時間間隔を確認します
ALLOW_TIMES:時間間隔内の訪問数を確認しますREFUSE_TIME:
侵入者のブロック時間
クライアントから渡されたIPをredisのキーとして使用します。クライアントが初めてアクセスするときに、キーと値のペアが作成され、そのライフサイクルがRECORD_TIMEとして設定されます。ここでは1秒に設定します。この秒の間に、ユーザーはインターフェイスに再度アクセスすると、対応する値が1ずつ増加します。存続期間中に値がALLOW_TIMESに追加されると、侵入者として設定され、REFUSE_TIME内でURLにアクセスできなくなります。つまり、IPがブロックされます。期間内にfalseを返し、侵入者が引き続きhttpインターフェイスにアクセスしようとすると、ブロック時間が更新されます。ここでは、httpDetectiveという名前のBeanとして登録されます。
4.検出クラスをインターセプターにマウントして、httpインターセプト検出を実現します
4.1カスタムインターセプター
インターセプターはtrueとfalseを返すことで発行するかどうかを決定するため、検査メソッドを返すには、上記の検出クラスを直接挿入するだけで済みます。
@Autowired
HttpDetective httpDetective;
@Bean
public HandlerInterceptor visitorRegistration(){
return new HandlerInterceptor(){
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return httpDetective.inspection(request.getRemoteAddr());
}
};
}
4.3スプリングブーツにインターセプターを登録する
Springboot登録インターセプターは、WebMvcConfigurerを継承し、addInterceptors(InterceptorRegistryレジストリ)メソッドでインターセプターを追加および変更する限り、非常に便利です。このクラスに@Configuratioとして注釈を付けることに注意してください。ここで、これ以上言う必要はありません。
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Resource
HandlerInterceptor visitorRegistration;
@Override
public void addInterceptors(InterceptorRegistry registry) {
System.out.println("添加拦截器");
// TODO Auto-generated method stub
registry.addInterceptor(visitorRegistration)
// 拦截路劲
.addPathPatterns("/**");
}
}
3つの機能テスト
例として開発した中古モールを使用し、まずサーバーを起動します
サーバーは正常に起動します
ブラウザを開いてhttpを必死にスワイプします(多くの人が私の手の速度に到達しない可能性があります。または、プログラムを作成してURLをスワイプすることもできます)
毎秒20秒スワイプするhttpリクエストでは、6回目以降のすべてのリクエストが傍受され、3分以内にアクセスできなくなっていることがわかります。
サーバーのredisには、対応するredisレコードもあります
4、要約とそれに続く言葉
関連する機能と安定した効率的なフレームワークが必要であることを知りたいのですが、それでも私は自分で突然または以前のアイデアを実装したいと思っています。スプリングブートフレームワークの全体的な非同期構造のために、コードに特定の逸脱がある場合があります。ただし、これはセキュリティに影響を与えることはなく、興味のある人はHttpDetectiveインターフェイスのより安定した効率的な実装を実装することもできます。これは私が真剣に書いた最初のcsdnです。私はあまり熟練していないため、時間がかかりました。完了までに3時間かかります。記事のタイプミスについてはご容赦ください。著者の方が熟練しています。何か問題や提案がある場合は、さらにアドバイスをお願いします。