你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

一段令人难以置信的烂代码

[复制链接]
gaosmile 发布时间:2020-9-28 10:24
在Facebook网站上有一个名为“Il Programmatore di Merda”(“ The Shitty Programmer”,中文俗译为“粑粑程序猿”)的社区。我经常上去浏览,这个网站经常分享一些写的烂的代码和有关编程的话题。这不,今天我就看到一段令人难以置信的烂代码,有图有真相:

微信图片_20200928102329.jpg
本周最烂代码

请各位仔细查看,上面的代码错误太多,我一时不知该从哪儿说起。

如果你是一个初级开发工程师,本篇文章会帮你理解上述代码中存在的一些严重的bug,希望各位同学引以为鉴。

128 行错误代码
我将上面的代码摘录下来,以便后面一起来讨论。代码如下:

  1. <script>
  2. function authenticateUser(username, password) {
  3.   var accounts = apiService.sql(
  4.     "SELECT * FROM users"
  5.   );

  6.   for (var i = 0; i < accounts.length; i++) {
  7.     var account = accounts [i];
  8.     if (account.username === username &&
  9.         account.password === password)
  10.     {
  11.       return true;
  12.     }
  13.   }
  14.   if ("true" === "true") {
  15.     return false;
  16.   }
  17. }

  18. $('#login').click(function() {
  19.   var username = $("#username").val();
  20.   var password = $("#password").val();

  21.   var authenticated = authenticateUser(username, password);

  22.   if (authenticated === true) {
  23.     $.cookie('loggedin', 'yes', { expires: 1 });
  24.   } else if (authenticated === false) {
  25.     $("error_message").show(LogInFailed);
  26.   }
  27. });
  28. </script>
复制代码

把代码复制完的一时之间,我竟不知道从何说起了。上述错误大致分为 3 类:

  • 安全问题
  • 基本编程概念问题
  • 代码格式化问题


2 安全问题

我们非常确定以下代码能够在客户端运行,因为它已经包含在两个<script>标记间(当然它用的是 jQuery 框架)。不要误会我的意思,这些代码即使是运行在服务器端也很糟糕,在客户端上运行这些代码会将数据库暴露给……每个用户。

让我们先来看一下authenticateUser函数:

  1. function authenticateUser(username, password) {
  2.   var accounts = apiService.sql(
  3.     "SELECT * FROM users"
  4.   );

  5.   for (var i = 0; i < accounts.length; i++) {
  6.     var account = accounts [i];
  7.     if (account.username === username &&
  8.         account.password === password)
  9.     {
  10.       return true;
  11.     }
  12.   }
  13.   if ("true" === "true") {
  14.     return false;
  15.   }
  16. }
复制代码

我们的代码在某些地方有个叫做apiServices的接口,它公开了一个.sql方法,可以对数据库进行 SQL 操作。这意味着,如果你在运行上述代码的浏览器上打开控制台,就可以执行各种查询,安全隐患简直无法比喻。例如,你不需要获得授权就可以这样做:

  1. apiService.sql("show tables;");
复制代码

调用上述 API,代码执行后会返回数据库的所有表名称。

我们暂且假装这不是一个特严重的问题。但是请各位接着往下看:

  1. if (account.username === username && account.password === password)
复制代码

所以,作者的意思是直接保存了用户所有的明文密码,而没有对它们进行MD5哈希处理?

这简直无法想象!现在我可以打开 Chrome 浏览器的调试器,直接查看每个用户的明文密码。

我非常确定,很大一部分用户会在社交网络、邮件服务、银行账户等服务中使用相同的用户名和密码。想象一下,别人可以在没有任何障碍下就可以拿到你的账户与密码,这是得多么地可怕。

作者尝试设置登录cookie 的方式也存在问题。代码如下:

  1. $.cookie('loggedin', 'yes', { expires: 1 });
复制代码

按照代码的意思,作者使用 jQuery 设置 cookie,让该 cookie 告知 Web 应用程序用户是否通过身份验证。

好吧,千万不要使用 JavaScript 来设置此类 cookie。

如果你有存储此类登陆信息的需求,那么使用 cookie 确实是最常见的解决方案,这没有什么问题!但是使用 JavaScript 设置它们意味着你无法设置httpOnly属性,这会导致每个恶意脚本都能轻而易举地访问和获取你的 cookie 内容。

是的,我知道,他们只是存储'loggedin': 'yes'的键值信息,可能不是上面我讲的那种情况,但总之这是一个糟糕的做法。

另外,打开 Chrome 控制台,我随时可以输入$ .cookie('loggedin','yes',{expires: 1000000000000})命令, 而且即使我没有用户帐户,也会永远保持登录状态。

3 基本编程概念问题
想说的话太多,但无奈时间有限。

很明显,authenticateUser函数写的就是一堆垃圾,该函数的实现充分表明作者缺乏一些基本的编程概念。

  1. function authenticateUser(username, password) {
  2.   var accounts = apiService.sql(
  3.     "SELECT * FROM users"
  4.   );

  5.   for (var i = 0; i < accounts.length; i++) {
  6.     var account = accounts [i];
  7.     if (account.username === username &&
  8.         account.password === password)
  9.     {
  10.       return true;
  11.     }
  12.   }
  13.   if ("true" === "true") {
  14.     return false;
  15.   }
  16. }
复制代码

代码作者为什么不只查询给定用户名和密码的用户,而是检索出数据库中的所有用户呢?如果该数据库中拥有数百万个用户怎么办?

还有前面我已经说过了,在这里我再提一下,为什么作者不对数据库中的明文密码进行哈希处理?

让我们接着看一下authenticateUser函数的返回值。

我们可以看到,该函数接收两个 string 类型的参数,最后返回一个布尔类型的值。所以,下面的代码即使很糟糕(明文密码),但也有一定的意义:

  1. for (var i = 0; i < accounts.length; i++) {
  2.   var account = accounts [i];
  3.   if (account.username === username &&
  4.       account.password === password)
  5.   {
  6.     return true;
  7.   }
  8. }
复制代码

上面代码的含义很清楚,“是否存在具有 X 用户名和 Y 密码的用户?是的,所以函数执行结果返回 true”。

但是下面这个代码的逻辑这样的:

  1. if ("true" === "true") { return false;}
复制代码

这根本没有任何道理!为什么函数不去掉永真条件判断,直接返回 false?继续接着分析后面的代码:

  1. $('#login').click(function() {
  2.   var username = $("#username").val();
  3.   var password = $("#password").val();

  4.   var authenticated = authenticateUser(username, password);

  5.   if (authenticated === true) {
  6.     $.cookie('loggedin', 'yes', { expires: 1 });
  7.   } else if (authenticated === false) {
  8.     $("error_message").show(LogInFailed);
  9.   }
  10. });
复制代码

使用 jQuery 获取属性值的代码部分没有什么问题。问题在于它如何处理loggedin 用户的 cookie。

以前讨论过这样一个问题,我可以在我的 Chrome 控制台输入$ .cookie('loggedin','yes',{expires:1}); 保持认证一整天,甚至都不需要一个帐号。

所以,这个网站到底是怎么确定我是谁的?也许它只是通过用户名 / 密码身份验证显示一些私人内容,所以它没有展示任何个人数据。总之,没有人知道代码为什么会这么写。

4 代码格式化问题

代码格式可能是整个代码中不太重要的部分,但我们可以很容易地判断出该开发人员复制 / 粘贴了某些网站上的代码。

下面的代码片段,我们可以看到开发者使用了双引号引用字符串:

  1. var username = $("#username").val();
  2. var password = $("#password").val();
复制代码

然而,下面的代码却又使用了单引号字符串:

  1. $.cookie('loggedin', 'yes', { expires: 1 });
复制代码

这些看起来可能没有那么重要,但实际上我们可以确定,开发人员可能已经从 StackOverflow 复制粘贴了一些代码,甚至都没有遵循整个代码库的代码规范来重写它们。当然,这只是一个小问题,但它表明开发人员并不真正关心和理解代码的工作方式,只是希望代码以某种方式工作。

大家不要误会,我每天都会在 Google 上进行搜索,但比起仅仅复制和粘贴代码来实现功能,理解代码的工作原理——比如理解如何设置 Cookie,实际上更为重要。如果由于某种原因整个进程中断了怎么办?你如何确定是脚本的哪一部分不起作用呢?

5 总结
我绝对可以确定上面的代码是伪造的。这是我第一次看到使用同步方式进行 SQL 查询:

  1. var accounts = apiService.sql( "SELECT * FROM users");
复制代码

通常,我希望查询功能的实现类似下面这样:

  1. var accounts = apiService.sql("SELECT * FROM users", (err, res) => { console.log(err); // some error console.log(res); // query result});
复制代码

或者这样:

  1. var accounts = await apiService.sql( "SELECT * FROM users");
复制代码

即使使用同步方式调用apiService.sql返回查询值(我对此表示怀疑),在内部也必须进行与数据库的连接、执行查询语句并发送返回查询结果,这些过程(你可能已经知道了)明显是不同步的。

但是,即使上面的代码不是伪造的,我也可以确信它是由初级开发人员编写的。我刚刚开始入行写代码的一段时间里,我很确定自己为之前的公司也写过这么糟糕的代码。

这个锅不能甩给初级开发人员。

让我们假设上面的代码是真实的。这里的初级开发人员正在竭尽所能实现功能。他 / 她尚未开始学习如何正确处理 SQL 查询、cookie 以及其他需要注意的技术点,这完全可以理解!

高级开发人员应该提供某种形式的指导,以确保初级开发人员可以理解他们的错误,保证这样的错误代码不会在生产环境中使用。

我也可以确认的是,有些公司其实并不真正在乎开发人员编写的代码质量。
代码能解决问题吗?——生产环境部署一下就知道了呀。代码是由初级开发人员编写的,甚至都没有高级开发人员的批准吗?——部署运行一下就知道结果了呀。
哎,Shit happens!

6 后记
我在 Reddit 对此进行了一番讨论后,一个非常给力的小伙伴分享了下面的 Reddit 话题:

“This JavaScript code powers a 1,500 user intranet application”
https://www.reddit.com/r/programminghorror/comments/66klvc/this_javascript_code_powers_a_1500_user_intranet

所以,是我错了。这些代码并不是伪造的!

收藏 评论0 发布时间:2020-9-28 10:24

举报

0个回答

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版