odoo 结合fail2ban
在配置fail2ban的时候遇到很多坑,现在记录下
先参考一篇博客的教程:
可以使用echo
命令来模拟日志的写入,不需要搭建日志服务
echo '2016-07-17 18:05:03 ERROR can not parse header when handling connection from 112.10.137.6:20463' >> /var/log/shadowsocks1.log
其中需要注意的一点 是,2016-07-17 18:05:03
时间不能随便设置,时间与当前时间不能相差太多,不然fail2ban 总是忽略.
如果按照上边的教程能够实现,再来尝试odoo服务.
odoo 用户登录使用odoo自带的功能即可,详情可参考上一篇博客
主要是数据库密码的防暴力破解,看了下源码,odoo并没有做相关的防范措施,要是被人恶意破解开,感觉就是灾难.
odoo 数据库密码可以尝试的方式有:备份,复制,删除,创建,还原,更改密码,所以要把控好这几入口
而且就算尝试密码错误后,后台日志没有记录,添加日志需要修改源码.
关于odoo 日志的时间
日志的时间使用的utc时区,与系统的时间总是相差8个小时,这点也需要做调整:
调整的方式参考:http://chenliy.com/post/330
调整的相关源码:
调整时区
import datetime class DBFormatter(logging.Formatter): def format(self, record): record.pid = os.getpid() record.dbname = getattr(threading.current_thread(), 'dbname', '?') return logging.Formatter.format(self, record) def formatTime(self, record, datefmt=None): now = datetime.datetime.now() + datetime.timedelta(hours=8) ct = time.localtime(time.mktime(now.timetuple())) print(time.tzname) if datefmt: s = time.strftime(datefmt, ct) else: t = time.strftime("%Y-%m-%d %H:%M:%S", ct) s = "%s,%03d" % (t, record.msecs) return s
添加日志打印
@http.route('/web/database/create', type='http', auth="none", methods=['POST'], csrf=False) def create(self, master_pwd, name, lang, password, **post): try: if not re.match(DBNAME_PATTERN, name): raise Exception(_('Invalid database name. Only alphanumerical characters, underscore, hyphen and dot are allowed.')) # country code could be = "False" which is actually True in python country_code = post.get('country_code') or False dispatch_rpc('db', 'create_database', [master_pwd, name, bool(post.get('demo')), lang, password, post['login'], country_code, post['phone']]) request.session.authenticate(name, post['login'], password) return http.local_redirect('/web/') except Exception as e: error = "Database creation error: %s" % (str(e) or repr(e)) _logger.info('{} -Action:database create, database auth failed'.format(request.httprequest.remote_addr)) return self._render_template(error=error) @http.route('/web/database/duplicate', type='http', auth="none", methods=['POST'], csrf=False) def duplicate(self, master_pwd, name, new_name): try: if not re.match(DBNAME_PATTERN, new_name): raise Exception(_('Invalid database name. Only alphanumerical characters, underscore, hyphen and dot are allowed.')) dispatch_rpc('db', 'duplicate_database', [master_pwd, name, new_name]) return http.local_redirect('/web/database/manager') except Exception as e: error = "Database duplication error: %s" % (str(e) or repr(e)) _logger.info('{} -Action:database duplicate, database auth failed'.format(request.httprequest.remote_addr)) return self._render_template(error=error) @http.route('/web/database/drop', type='http', auth="none", methods=['POST'], csrf=False) def drop(self, master_pwd, name): try: dispatch_rpc('db','drop', [master_pwd, name]) request._cr = None # dropping a database leads to an unusable cursor return http.local_redirect('/web/database/manager') except Exception as e: error = "Database deletion error: %s" % (str(e) or repr(e)) _logger.info('{} -Action:database drop, database auth failed'.format(request.httprequest.remote_addr)) return self._render_template(error=error) @http.route('/web/database/backup', type='http', auth="none", methods=['POST'], csrf=False) def backup(self, master_pwd, name, backup_format = 'zip'): try: odoo.service.db.check_super(master_pwd) ts = datetime.datetime.utcnow().strftime("%Y-%m-%d_%H-%M-%S") filename = "%s_%s.%s" % (name, ts, backup_format) headers = [ ('Content-Type', 'application/octet-stream; charset=binary'), ('Content-Disposition', content_disposition(filename)), ] dump_stream = odoo.service.db.dump_db(name, None, backup_format) response = werkzeug.wrappers.Response(dump_stream, headers=headers, direct_passthrough=True) return response except Exception as e: _logger.exception('Database.backup') error = "Database backup error: %s" % (str(e) or repr(e)) _logger.info('{} - Action:database backup, database auth failed'.format(request.httprequest.remote_addr)) return self._render_template(error=error) @http.route('/web/database/restore', type='http', auth="none", methods=['POST'], csrf=False) def restore(self, master_pwd, backup_file, name, copy=False): try: data_file = None db.check_super(master_pwd) with tempfile.NamedTemporaryFile(delete=False) as data_file: backup_file.save(data_file) db.restore_db(name, data_file.name, str2bool(copy)) return http.local_redirect('/web/database/manager') except Exception as e: error = "Database restore error: %s" % (str(e) or repr(e)) _logger.info('{} - Action:database restore, database auth failed'.format(request.httprequest.remote_addr)) return self._render_template(error=error) finally: if data_file: os.unlink(data_file.name) @http.route('/web/database/change_password', type='http', auth="none", methods=['POST'], csrf=False) def change_password(self, master_pwd, master_pwd_new): try: dispatch_rpc('db', 'change_admin_password', [master_pwd, master_pwd_new]) return http.local_redirect('/web/database/manager') except Exception as e: error = "Master password update error: %s" % (str(e) or repr(e)) _logger.info('{} - Action:database change_password, database auth failed'.format(request.httprequest.remote_addr)) return self._render_template(error=error)
fail2ban 配置:
# /etc/fail2ban/jail.local [odoo] enabled = true port = http,https bantime = 8100 # 900s (15 min) + 7200s (2 hours diffecence in odoo log and systemtime) maxretry = 4 findtime = 8100 # 900s (15 min) + 7200s (2 hours diffecence in odoo log and systemtime) # logpath = /var/log/test.log logpath = /opt/logs/odoo/odoo12_dev_stdout.log
# /etc/fail2ban/filter.d/odoo.conf [INCLUDES] # Read common prefixes. If any customizations available -- read them from # common.local before = common.conf [DEFAULT] _daemon = odoo [Definition] failregex = odoo.addons.web.controllers.main: <HOST> -Action:database .*?, database auth ignoreregex = # maxlines = 1 # journalmatch = _SYSTEMD_UNIT=sshd.service + _COMM=sshd
重启fail2ban :service fail2ban reload
到这里不出意外的话,可以看到fail2ban 的测试日志:fail2ban set loglevel TRACEDEBUG
问题延申:
- odoo服务是由其他nginx 服务器反向代理的, 那么这么配置就没有太大的意义,目前觉得可行的办法是将当前的日志文件共享到nginx 所在的服务器中,然后使用nginx 服务器的fail2ban 来禁用ip
本文来自博客园,作者:那时一个人,转载请注明原文链接:https://www.cnblogs.com/qianxunman/p/15909029.html
标签:
odoo
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 一文读懂知识蒸馏
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下