웹페이지의 국가별 액세스 수 시각화
13170 단어 ShellScriptnginxPython3아파치centos7
목적
분명한 해외로부터의 공격적 접근을 이해하기 쉽게
개요
사전 준비
(방법은 몇 가지 있으므로 직접 확인해보십시오)
를 사용합니다.
GeoIP을 사용하므로 등록하십시오.
라이선스와 취득 방법이 작년 말에 변경이 있었으므로, 여기 등을 참고해 보세요
환경
서버: 클라우드(AWS lightsail)
OS: CentOS 7.8
웹 서버: apache 2.4.6
Python: 3.6.4
apacheRoot:/var/www/html/
apache 로그:/var/log/httpd/
[root@fishkiller ~]# cat /etc/centos-release
CentOS Linux release 7.8.2003 (Core)
[root@fishkiller ~]# httpd -v
Server version: Apache/2.4.6 (CentOS)
Server built: Apr 2 2020 13:13:23
[root@fishkiller ~]# python --version
Python 3.6.4
[root@fishkiller ~]# cat /etc/httpd/conf/httpd.conf|grep Root|grep -v "\#"
ServerRoot "/etc/httpd"
DocumentRoot "/var/www/html"
[root@fishkiller httpd]# pwd
/var/log/httpd
환경은 정직 python이 3 계이면 무엇이든 좋다.
[root@fishkiller ~]# pwd
/root
[root@fishkiller ~]# ls
app bin
[root@fishkiller ~]# ls app/
accessip
원하는 곳에 원하는대로 작업 디렉토리를 만드십시오.
디렉토리
~/ap
|--accessip
|--main.py
|--GeoLite2-City.mmdb
로그에서 액세스한 IP 추출
cat /var/log/httpd/access_`date +%Y%m`$((`date +%d`-1)).log|awk '{print $1}'|sort > /root/app/httpd-ip.txt
미안. py
#!/usr/bin/python
import numpy as np
import matplotlib as mpl
mpl.use('Agg')
import matplotlib.pyplot as plt
import re
import requests
import geoip2.database
import folium
import japanize_matplotlib
# Line-notifier設定
token = 'トークン'
api = 'https://notify-api.line.me/api/notify'
#Geoipのデータベースを読み込む
reader = geoip2.database.Reader('/root/bin/log/GeoLite2-City.mmdb')
# 読み込むファイルを開く
f = open('/root/bin/log/httpd-ip.txt')
lines = f.readlines()
f.close()
country = []
city = []
def main():
map = folium.Map(location=[35,135],zoom_start=4)#map
for line in lines:
ip = line.rstrip('\n')
print("IP",ip) #IP
data = reader.city(ip)
country.append(data.country.name)
print ("国:", data.country.name) #国
#print ("Subdivisions: ", data.subdivisions.most_specific.name)#州・県
city.append(data.city.name)
print ("都市: ", data.city.name) # 市町村
# print ("経度,緯度: ",data.location.longitude,data.location.latitude)
#print ("経度: ",data.location.longitude)
#print ("緯度: ",data.location.latitude)
folium.Marker([data.location.latitude,data.location.longitude],popup=data.city.name).add_to(map) # ([経度,緯度],popup="表示名")
#print ("軽度: ", data.location.latitude)
#print ("緯度: ", data.location.longitude)
#print ("タイムゾーン:", data.location.time_zone)
map.save('/root/app/accessip/http_map.html')
count = len(country)
CN = country.count('China') #中国
CA = country.count('Canada') #カナダ
US = country.count('United States') #アメリカ
VN = country.count('Vietnam') #ベトナム
PH = country.count('Philippines') #フィリピン
RU = country.count('Russia') #ロシア
UA = country.count('Ukraine') #ウクライナ
IT = country.count('Italy') #イタリア
ES = country.count('Spain') #スペイン
TW = country.count('Taiwan') #台湾
KR = country.count('Republic of Korea') #韓国
IN = country.count('India') #インド
JP = country.count('Japan') #日本
others = count-CN-CA-US-VN-PH-RU-UA-IT-ES-TW-KR-IN-JP
circle(CN,CA,US,VN,PH,RU,UA,IT,ES,TW,KR,IN,JP,others)
mess(CN,CA,US,VN,PH,RU,UA,IT,ES,TW,KR,IN,JP,others,count)
check(CN,CA,US,VN,PH,RU,UA,IT,ES,TW,KR,IN,JP,others,count)
cplot(CN,CA,US,VN,PH,RU,UA,IT,ES,TW,KR,IN,JP)
def circle (CN,CA,US,VN,PH,RU,UA,IT,ES,TW,KR,IN,JP,others):
graph = np.array([CN,CA,US,VN,PH,RU,UA,IT,ES,TW,KR,IN,JP,others])
#x = ["CN","CA","US","VN","PH","RU","UA","IT","ES","TW","KR","IN","others"]
x = ["中国","カナダ","アメリカ","ベトナム","フィリピン","ロシア","イギリス","イタリア","スペイン","台湾","韓国","インド","日本","その他"]
plt.style.use('ggplot')
plt.rcParams.update({'font.size':15})
plt.pie(graph,labels=x,autopct=lambda p:'{:.1f}%'.format(p) if p>=5 else '')
plt.savefig('/root/app/accessip/apache-access.png')
# plt.show()
def cplot(CN,CA,US,VN,PH,RU,UA,IT,ES,TW,KR,IN,JP):
map1 = folium.Map(location=[35, 135], zoom_start=3)
states = (
{'lat': 39.5427, 'lon': 116.2350, 'value': CN, 'name': '中国'},
{'lat': 45.4215, 'lon': -75.6971, 'value': CA, 'name': 'カナダ'},
{'lat': 38.907192, 'lon': -77.036871, 'value': US, 'name': 'アメリカ'},
{'lat': 21.0279, 'lon':105.851, 'value': VN, 'name': 'ベトナム'},
{'lat': 14.609, 'lon': 121.0222, 'value': PH, 'name': 'フィリピン'},
{'lat': 55.7558, 'lon': 37.6173, 'value': RU, 'name': 'ロシア'},
{'lat': 50.4501, 'lon': 30.5234, 'value': UA, 'name': 'ウクライナ'},
{'lat': 41.9027, 'lon': 12.4963, 'value': IT, 'name': 'イタリア'},
{'lat': 40.4167, 'lon': -3.7037, 'value': ES, 'name': 'スペイン'},
{'lat': 25.251, 'lon': 121.3154, 'value': TW, 'name': '台湾'},
{'lat': 37.34, 'lon': 126.59, 'value': KR, 'name': '韓国'},
{'lat': 20.5936, 'lon': 78.9628, 'value': IN, 'name': 'インド'},
{'lat': 35.4122, 'lon': 139.4130, 'value': JP, 'name': '日本'}
)
# 円の大きさをわかりやすくするための重み
WEIGHT = 0.6
# 都市ごとにマーカーを追加(数が増えると辛いため、一括追加が今後の課題)
for state in states:
folium.CircleMarker(
[state['lat'], state['lon']],
radius=state['value'] * WEIGHT,
popup=state['name'],
color='#3186cc',
fill_color='#3186cc',
).add_to(map1)
map1.save('/root/app/accessip/http_map1.html')
def mess (CN,CA,US,VN,PH,RU,UA,IT,ES,TW,KR,IN,JP,others,count):
## Lineに送る
# meesage = 送るメッセージ
message = '\n' + '中国:' + str(CN/count*100) + '%\n' + 'カナダ:' + str(CA/count*100) + '%\n' + 'アメリカ:' + str(US/count*100) + '%\n' + 'ベトナム:' + str(VN/count*100) + '%\n' + 'フィリピン:' + str(PH/count*100) + '%\n' + 'ロシア:' + str(RU/count*100) + '%\n' + 'ウクライナ:' + str(UA/count*100) + '%\n' + 'イタリア:' + str(IT/count*100) + '%\n' + 'スペイン:' + str(ES/count*100) + '%\n' + '台湾:' + str(TW/count*100) + '%\n' + '韓国:' + str(KR/count*100) + '%\n' + 'インド:' + str(IN/count*100) + '%\n' + '日本' + str(JP/count*100) + '%\n' +'その他:' + str(others/count*100) + '%\n'+'MAP: '+'http://fishkiller.info/banmap/index.html'+'\n'+'国MAP: '+'http://18.177.113.234/httpd/map1.html'
payload = {'message': message}
files = {"imageFile": open("apache-access.png", "rb")}
#headers = {'Authorization': 'Bearer ' + line_notify_token}
#line_notify = requests.post(line_notify_api, data=payload, headers=headers)
headers = {'Authorization': 'Bearer ' + token}
line_notify = requests.post(api, data=payload, headers=headers, files=files)
def check (CN,CA,US,VN,PH,RU,UA,IT,ES,TW,KR,IN,JP,others,count):
print("中国:",CN)
print(CN/count*100,"%")
print("カナダ:",CA)
print(CA/count*100,"%")
print("アメリカ:",US)
print(US/count*100,"%")
print("ベトナム:",VN)
print(VN/count*100,"%")
print("フィリピン:",PH)
print(PH/count*100,"%")
print("ロシア:",RU)
print(RU/count*100,"%")
print("ウクライナ:",UA)
print(UA/count*100,"%")
print("イタリア:",IT)
print(IT/count*100,"%")
print("スペイン:",ES)
print(ES/count*100,"%")
print("台湾:",TW)
print(TW/count*100,"%")
print("韓国:",KR)
print(KR/count*100,"%")
print("インド:",IN)
print(IN/count*100,"%")
print("日本",JP)
print(JP/count*100,"%")
print("その他:",others)
print(others/count*100,"%")
print(count)
if __name__ == "__main__":
main()
코드 하나로 정리해 깨끗하지 않다・・・
def 마다 각각 따로 하고, main 은 실행으로 하는 것만이 좋다.
그 중 수정합니다. . .
main : 다른 것을 인수 넣어 실행한다. 왠지 http_map.html 여기서 만들고 있다. . . cityplot적인 함수로서 정의해 봅시다・・・
circle : 원형 차트 만들기
cplot : 국가별 비율 맵 만들기(http_map1.html)
mess : LINEnotifier에게 메시지 보내기
check : 확인하듯이 모두 출력하고 있다
위의 프로그램을 실행하면
이런 느낌으로 LINE이 보내집니다.
추가 작업 디렉토리에
- http_map.html
- http_map1.html
- apache-access.png
가 생성됩니다.
이번에는 생성되는 장소를 작업 디렉토리로하고 있습니다만, 그다지 좋지 않다고 생각하기 때문에
/var/log 부하나/usr/src/하하 등에 그것용의 디렉토리를 두도록 하는 편이 좋을 것 같습니다.
그리고는 각각 두고 싶은 web 컨텐츠 디렉토리에 설치하면 좋을 뿐.
콘텐츠 설치
콘텐츠 디렉토리
/var/www/html
|--map
|--index.html
|--http_map1.html
|-- log
|-- 日付.jpg
### accessip-set
```accessip-set.sh
##!/bin/bash
SAVE_DIR="/var/www/html/map"
cp /root/app/accessip/apache-access.png ${SAVE_DIR}/log/`date +%Y%m%d`.jpg
cp -f /root/bin/log/http_map.html ${SAVE_DIR}/index.html
cp -f /root/bin/log/http_map1.html ${SAVE_DIR}/
로그 위치나 컨텐츠 설치 위치 등은 조정해 주십시오.
index.html(http_map.html)
http_map1.html
이런 느낌이 된다.
정기 실행
원하는대로 cron을 설정하십시오. . .
[root@fishkiller ~]# crontab -l
# apachelog ip
0 5 * * * cat /var/log/httpd/access_`date +%Y%m`$((`date +%d`-1)).log|awk '{print $1}'|sort > /root/app/accessip/httpd-ip.txt
1 5 * * * /root/.pyenv/shims/python /root/app/accessip/apacheip.py
2 5 * * * /root/bin/apache-access.sh
※python을 cron으로 실행할 때는 풀 패스로 쓸 필요가 있습니다.
[root@fishkiller ~]# which python
/root/.pyenv/shims/python
⇓ 1개의 쉘에 정리해 버립니다.
[root@fishkiller ~]# crontab -l
# apachelog ip
0 5 * * * /root/bin/apache-ip.sh
아파체 위치 p. sh
##!/bin/bash
cat /var/log/httpd/access_`date +%Y%m`$((`date +%d`-1)).log|awk '{print $1}'|sort > /root/app/accessip/httpd-ip.txt
/root/.pyenv/shims/python /root/app/accessip/apacheip.py
/root/bin/apache-access.sh
같은 IP를 계산하지 않으려면
첫 번째에 uniq를 추가하면 OK
cat /var/log/httpd/access_`date +%Y%m`$((`date +%d`-1)).log|awk '{print $1}'|sort |uniq > /root/app/accessip/httpd-ip.txt
위의 cron 설정에서는 매일 아침 5시 LINE 와 버리므로,,,
7시 정도로 해 두면 좋을지도 모릅니다.
요약
이번은 apache의 로그로 했습니다만, IP의 리스트가 있으면 좋을 뿐이므로, fial2ban으로 BAN했다나 mail의 발송주등 로그로부터 IP 추출할 수 있습니다.
예를 들어, 자신의 fail2ban의 BAN 한 IP로하면 거의 거의 중국이됩니다.
특정 시간만 추출하면 특정 시간의 것도 할 수 있고, 다양한 응용은 효과가있을 것 같습니다.
현재 상태, 국가를 지정하고 있는 것과 국가를 추가할 때 귀찮은 등이 향후 개선점이라고 생각합니다.
이것을 신경쓰고, 자신의 서버에의 액세스가 어떤 곳에서 오는지 의식해 보는 것도 좋을지도 모릅니다.
Reference
이 문제에 관하여(웹페이지의 국가별 액세스 수 시각화), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/sakana0406/items/c9cb4df7293b3258eeb1
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
Reference
이 문제에 관하여(웹페이지의 국가별 액세스 수 시각화), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/sakana0406/items/c9cb4df7293b3258eeb1텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)