问题描述
因此,我已将 Web 应用程序的身份验证日志转发到 graylog,现在我想为 brutefroce 实施一些警报。 从 webapp 发送到 Graylog 的每条记录都包含一些信息,其中包括用户名和哈希密码。 我想通过查询来查找对 login 和 hashed_password 字段的唯一组合进行计数的警报。
我知道如何设置警报,但找不到有效的查询。
例如,我有这个日志:
... login=foo hashed_password=XXXX ...
... login=foo hashed_password=XXXX ...
... login=foo hashed_password=XXXX ...
... login=foo hashed_password=YYYY ...
... login=foo hashed_password=ZZZZ ...
... login=foo hashed_password=AAAA ...
... login=foo hashed_password=AAAA ...
... login=foo hashed_password=BBBB ...
我想找到一个查询,这两个字段的每个组合只打印一次。我试过很多次,但都没有成功。 从日志 aboce,它应该只打印:
... login=foo hashed_password=XXXX ...
... login=foo hashed_password=YYYY ...
... login=foo hashed_password=ZZZZ ...
... login=foo hashed_password=AAAA ...
... login=foo hashed_password=BBBB ...
我尝试过的一些查询如下:
auth:"error" AND distinct(login+hashed_password)
auth:"error" AND count(distinct(login+hashed_password))
auth:"error" AND count(login(hashed_password))
我运行的是graylog 4.0版本和Elastic Oss 7.10,所有服务器都是Centos7
解决方法
首先,坏消息。 Graylog 不支持 Elasticsearch v7.11。 7.10 是最新支持的版本。
第二,更多坏消息。 Graylog 不支持您尝试在查询中使用的任何功能。支持的语法可以在这里找到:https://docs.graylog.org/en/4.0/pages/searching/query_language.html?highlight=syntax#search-query-language
您可以使用仪表板做一些您想做的事情。我还建议尝试聚合事件(警报/事件)以在这些情况发生时提醒您。
,我找到了解决问题的方法: 我只是按 IP 源和登录对查询结果进行分组,然后我添加了这个条件来创建事件:
/* eslint-disable no-shadow */
/* eslint-disable react-native/no-inline-styles */
/* eslint-disable prettier/prettier */
import React,{useState,useEffect} from 'react';
import {TextInput,SafeAreaView,ScrollView,TouchableWithoutFeedback,Text,View,StyleSheet,Image} from 'react-native';
import Header from '../components/Header';
import {localizdStrings} from '../LocalizedConstants';
import { useNavigation } from '@react-navigation/native';
import CheckBox from '@react-native-community/checkbox';
import LinearGradient from 'react-native-linear-gradient';
import { SocialIcon } from 'react-native-elements';
import AsyncStorage from '@react-native-community/async-storage';
import GradientHeader from 'react-native-gradient-header';
import LocalizedStrings from 'react-native-localization';
import { showMessage } from 'react-native-flash-message';
import API from '../Config/API';
import axios from 'axios';
const LoginScreen = ({props}) => {
const navigation = useNavigation();
const [email,setEmail] = useState('');
const [password,setPassword] = useState('');
const [toggleCheckBox,setToggleCheckBox] = useState(false);
const showErrorMessage = (message,type) => {
return showMessage({
message: message,type: type,color: '#ffffff',fontSize: 14,fontWeight: 'bold',backgroundColor: '#0C254B',});
};
const ValidateEmail = (inputText) => {
var mailformat = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/;
if (inputText.match(mailformat)) {
return true;
}
else {
return false;
}
};
const validate = async () =>{
if (email === '' || email === undefined || email === null) {
return showErrorMessage("Email can't be blank",'danger');
}
else if (ValidateEmail(email) === false) {
return showErrorMessage('Enter a valid Email address','danger');
}
else if (password === '' || password === undefined || password === null) {
return showErrorMessage("Password can't be blank",'danger');
}
else {
// const data = JSON.stringify({
// 'email': email,// 'password': password,// });
const options = {
method: 'post',headers:{'Content-type': 'application/json'},url: 'http://localhost:8080/api/auth/signin',data: {
email: email,password: password,},transformResponse: [(data) => {
return data;
}]
};
const res = await axios(options).then((res)=>{
if (res.data.success === true){
//navigation.navigate('Auth');
navigation.navigate('Home');
// navigation.navigate('Service',{screen:'Doppler'});
//showErrorMessage(response.data.message,'success')
}
console.log(res.status);
}).catch((error)=> {
console.log(error);
});
}
};
return (
<SafeAreaView style={styles.outerContainer}>
<View style={{flex:1}}>
<Header />
<ScrollView style={styles.scrollView}>
<TextInput
placeholder= {localizdStrings.EmailOrMobile}
style={styles.TextInput}
onChangeText={(email) => setEmail(email)}
value={email}
keyboardType = {'email-address'}
autoCapitalize = "none"
autoCorrect = {false}
/>
<TextInput
placeholder= {localizdStrings.Password}
style={styles.TextInput}
onChangeText={(password) => setPassword(password)}
value={password}
autoCapitalize = "none"
returnKeyType={'done'}
secureTextEntry={true}
autoCorrect = {false}
/>
<View style={{flexDirection:'row',marginLeft:20,width:380,padding:10}}>
<View style={{flexDirection:'row',justifyContent:'flex-start',alignItems:'center'}}>
<View style={styles.rememberMe}>
<CheckBox
disabled={false}
value={toggleCheckBox}
tintColors={{true: '#ff0000'}}
onValueChange={(newValue) => setToggleCheckBox(newValue)}
/>
<Text>{localizdStrings.RememberMe}</Text>
</View>
</View>
<View style={{flexDirection:'row',justifyContent:'flex-end',alignItems:'center',marginLeft:50 }}>
<View style={styles.forgetPass}>
<Text style={{color:'grey'}}>{localizdStrings.ForgetThePassword}</Text>
</View>
</View>
</View>
<TouchableWithoutFeedback onPress={() => validate()}>
<LinearGradient start={{x: 1,y: 0}} end={{x: 0,y: 0}} colors={['#29B6F6','#29B6F6','#0231C1']} style={styles.gradientStyle}>
<View style={styles.Loginbutton}>
<Text style={{fontWeight:'bold',fontSize:20,color:'white'}}>{localizdStrings.Login}</Text>
</View>
</LinearGradient>
</TouchableWithoutFeedback>
<View style={styles.quickAcess}>
<Text style={{fontWeight:'bold',marginTop:5}}> {localizdStrings.OrQuickAccessWith} </Text>
<View style={{ margin:5}}>
<TouchableWithoutFeedback >
<View style={styles.button}>
<Image source={require('../images/facebook.png')}
style={styles.socialIcon}
/>
<Text style={styles.socialLoginText}>{localizdStrings.Facebook}</Text>
</View>
</TouchableWithoutFeedback>
<TouchableWithoutFeedback>
<View style={styles.button}>
<Image source={require('../images/google.png')}
style={styles.socialIcon}
/>
<Text style={styles.socialLoginText}>{localizdStrings.Google}</Text>
</View>
</TouchableWithoutFeedback>
<TouchableWithoutFeedback onPress={()=> navigation.navigate('RegisterScreen')}>
<Text style={{marginLeft:95,marginRight:120,fontWeight:'bold',fontSize:18}}>{localizdStrings.CreateANewAccount}</Text>
</TouchableWithoutFeedback>
<View style={{marginLeft:150,marginRight:150}}>
<Image source={require('../images/color_logo.png')} style={{resizeMode:'contain',height:80,width:100}} />
<Image source={require('../images/labelwhite.png')} style={{resizeMode:'contain',width:100}} />
</View>
</View>
</View>
</ScrollView>
</View>
</SafeAreaView>
);
};
export default LoginScreen;
const styles = StyleSheet.create({
outerContainer:{
flex:1,Loginbutton: {
alignItems: 'center',paddingLeft: 60,paddingRight:60,paddingBottom:10,paddingTop:10,borderRadius:20,marginBottom:10,marginLeft: 40,marginRight: 40,height:50,socialLoginText:{
color:'#00838F',//marginLeft:-50,paddingLeft:40,socialIcon:{
marginRight:50,marginLeft:-50,scrollView: {
backgroundColor: 'white',marginTop:100,text: {
fontSize: 42,TextInput: {
height: 50,flex: 1,paddingLeft: 20,paddingRight: 20,borderColor: '#0277BD',borderRadius: 30,borderWidth: 1,marginBottom:5,marginTop:40,rememberMe:{
flexDirection:'row',padding:10,marginLeft: 5,forgetPass:{
flexDirection:'row',gradientStyle:{
alignItems: 'center',quickAcess:{
alignItems:'center',button: {
alignItems: 'center',backgroundColor: 'white',borderWidth:1,borderColor:'#0277BD',borderRadius:8,flexDirection:'row',margin:15,});
具有类似警报的相同事物,我在其中放置了这些条件:
card(hashed_password) > 15
我用相同的声音分组的地方。
,我建议使用 GROK 模式仅过滤掉包含您要查找的信息(登录并通过)的消息。
GROK 模式允许我修剪日志,删除所有无用信息并仅在特定字段名称下保留我需要的信息,这在您需要监控可疑登录时非常有用。
例如:在您的情况下,您可以创建一个名为 "login_failed_foo" 的字段,然后在该字段的出现次数达到某个点时设置警报。