上个图,各位自己细品,不信的可以核实。
当面交易:
1)在对方电脑里看到源码;
2)现场对接官网核实识别率;
3)看着源码从他的设备转移到你的设备上,并且成功运行起来。
对于小号而言,最好接受第一条建议,防止跑路。 远程交易必须添加微信或者有年限和等级正常有使用痕迹的QQ,微信的朋友圈起码是超过其意图开始(打算卖模型)的年限的,能客观观察到对方是个真实的存在,信息暴露越少越不真实,毕竟万一被骗,这是能报警维权唯一的手段,诉讼文书才能知道该寄给谁。
综合以上,如果对方能接受以上全部要求,恭喜你们,不会花冤枉钱,我十分赞成你们交易,如果以各种理由回避或拒绝暴露真实的自己,建议大家要小心了。还有很重要的一个途径,岁月的痕迹不会骗人,看看项目开发的历史进程和发展轨迹:
去年我在云栖社区也做过技术分享直播,都有痕迹可以查的。
本文将通过一个案例,来向大家展示代码安全的重要性。
首先事情的经过是这样的,我几百年前在知乎发的一个评论突然给举报了,我已经放弃了最终的挣扎,但是我还是好奇,究竟是什么仇什么怨,然而我发现对方是一个小号,就存粹注册过来发这些信息的小号,下面来看看事件经过。
然后我看到这个沉了一个世纪的文章多了一条钓鱼评论:
顺藤摸瓜,找到作者,好家伙,上来也开始说自己98识别率了,我当时实测过他接口也就90左右, 跟他发起了好友请求,我一共申请过两次,第一次是他刚在github发链接的时候推送给我的,顺着找到了他的文章,那时我没把他当对手,我只是出于好奇,确认对方是不是找到了我在生成器里面埋的陷阱,这对我来说就像是埋宝藏的人看人闯关一样。第二次申请是间隔许久了,对方始终认为我不怀好意。 甚至于,现在还一直把截图挂着呢。通过作者的知乎文章,找到一个链接。
通过链接,打开作者的网站:
直接送模型,下载下来,
好家伙,就这?
解压可见,pyinstaller打包,老哥估计初学者,不懂得混淆代码。拿到颜色处理的函数,是不是熟悉的味道,你们猜的没错。
这段代码可见(源码在文末),出自okfu老哥手笔:https://blog.csdn.net/okfu_DL/article/details/90379583,
最早, 是源自我这篇方案里面的思路:https://blog.csdn.net/kerlomz/article/details/105974823
对比一下那个老哥博客写的:
我在这篇文章写过作者生成器的出处:https://blog.csdn.net/kerlomz/article/details/110676114。作者说自己没用,全部自己写的,那么我是相信作者是偶然路过这个包含生成代码的项目并且留下足迹的。
不过作者的口气似乎在表达,“自己并没有参考任何人的方法和思路”,并且英数的识别率很像是在暗示总体识别率很高。
看他的模型,还是比较入门水准的,Placeholder_1:0 说明了一切,懂得都懂。我不信不同识别率版本的模型用的还不是同一套训练代码,如果说不懂得代码复用那就更……
这里不多做评论了,还有模型加载等等的问题。
反编译这些没有任何技术含量,首先90识别率是达到商用水准的最低标准了,作者不懂得保护模型,这里该引以为戒,以为简单打包,几行代码就能做限制了,需要更正这种错误的观念。
方便你们比对,附上企业级训练和部署框架
训练:https://github.com/kerlomz/captcha_trainer
部署:https://github.com/kerlomz/captcha_platform
事实证明,轻易就拿到了源码:
#! /usr/bin/env python 3.6 (3379)
#coding=utf-8
# Compiled at: 1969-12-31 18:00:00
from gevent import monkey
from gevent.pywsgi import WSGIServer
monkey.patch_all()
import os, cv2, re, io, base64, numpy as np, tensorflow as tf, json, http.client, time
from PIL import Image
from flask import Flask, request, Response
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
os.environ['CUDA_VISIBLE_DEVICES'] = '2'
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
model_path = './model_frozen/model_win.pb'
app = Flask(__name__)
batch_size = 1
h = 64
w = 164
chanel = 3
graph = tf.compat.v1.Graph()
sess = tf.compat.v1.Session(graph=graph)
with tf.io.gfile.GFile(model_path, 'rb') as (f):
graph_def = tf.compat.v1.GraphDef()
graph_def.ParseFromString(f.read())
with graph.as_default():
tensors = tf.import_graph_def(graph_def, return_elements=['Placeholder:0', 'Placeholder_1:0',
'decode_conversion/SparseToDense:0'])
def get_web_time(host='42.192.80.101:8089'):
try:
conn = http.client.HTTPConnection(host)
conn.request('GET', '/')
res = conn.getresponse()
ts = res.getheader('date')
ltime = time.strptime(ts[5:25], '%d %b %Y %H:%M:%S')
return list(ltime)
except ConnectionError:
return 'network_error'
def get_charsets():
charsets = u'*123456789ABCDEFGHIJKLMNPQRSTUVWXYZ...此处省略几千字'
charsets = re.sub('\n|\t|', '', charsets)
charsets = list(set(list(charsets)))
charsets = sorted(charsets)
charsets = ('').join(charsets)
charsets = charsets.encode('utf-8').decode('utf-8')
return charsets
def color_convert(image, src_color):
if src_color == 'b':
dst_image = cv2.cvtColor(image.copy(), cv2.COLOR_RGB2BGR)
else:
if src_color == 'e':
dst_image = image[:, :, :].copy()
dst_image[:, :, 2] = 255 - dst_image[:, :, 2]
else:
if src_color == 'y':
dst_image = cv2.bitwise_not(image.copy())
dst_image = cv2.cvtColor(dst_image, cv2.COLOR_RGB2BGR)
else:
raise ValueError
return dst_image
def recognize(batch_image):
result = sess.run(tensors[2], {
tensors[0]: batch_image, tensors[1]: [w]})
text = ('').join([get_charsets()[v] for v in result[0] if v != -1])
text = text.replace('*', '')
return text
@app.route('/captcha', methods=['POST'])
def captcha_outer():
web_time = get_web_time()
if web_time == 'network_error':
return Response(json.dumps({
'code': 'network error'}, ensure_ascii=False), mimetype='application/json')
year = web_time[0]
month = web_time[1]
day = web_time[2]
if year == 2020:
pass
else:
if year == 2021:
if month == 1:
if day <= 11:
pass
return Response(json.dumps({
'code': 'Probation Expired,QQ3421366528'}, ensure_ascii=False), mimetype='application/json')
try:
res = request.data[0:int(request.content_length)]
res = json.loads(res, encoding='utf-8')
key = res['key']
image_bin = base64.b64decode(str(res['image']))
image_byte = io.BytesIO(image_bin)
image = Image.open(image_byte)
image_cv = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
except ValueError:
return Response(json.dumps({
'code': 'data error'}, ensure_ascii=False), mimetype='application/json')
if key == '00':
image = Image.fromarray(cv2.cvtColor(color_convert(image_cv, 'e'), cv2.COLOR_BGR2RGB))
else:
if key == '01':
pass
else:
if key == '02':
image = Image.fromarray(cv2.cvtColor(color_convert(image_cv, 'y'), cv2.COLOR_BGR2RGB))
else:
if key == '03':
image = Image.fromarray(cv2.cvtColor(color_convert(image_cv, 'b'), cv2.COLOR_BGR2RGB))
else:
return Response(json.dumps({
'code': 'key error'}, ensure_ascii=False), mimetype='application/json')
batch_images = np.zeros(shape=(batch_size, h, w, chanel), dtype=np.float32)
batch_image_widths = []
image = image.resize((164, 64), Image.ANTIALIAS)
image = np.array(image, np.float32)
image = image / 255
batch_images[0, :, :, :] = image
batch_image_widths.append(image.shape[1])
text = recognize(batch_images)
return Response(json.dumps({
'code': text}, ensure_ascii=False), mimetype='application/json')
if __name__ == '__main__':
http_server = WSGIServer(('127.0.0.1', 8808), app)
http_server.serve_forever()