在数字化时代,数字资产的存储、归档和保护变得尤为重要,可能需要持续数十年甚至数百年。数字资产管理系统主要关注资产的获取和用户访问,但资产本身如何呢?人们花费大量时间创建视频、图像和其他媒体,因此定期验证数字资产的数据完整性并在发现差异时发出警报是有意义的。以下是一个使用SHA-256校验和的控制台应用程序示例。
本文介绍的程序是一个为.NET4.0编写的控制台应用程序,它使用SHA-256校验和来验证文件夹及其子文件夹中所有文件的数据完整性。如果发现文件的校验和值发生变化,则通过电子邮件通知技术或业务负责人。程序还会报告文件总数、未更改文件数和新文件数,并将摘要报告写入电子邮件正文,附加两个包含详细信息的电子表格(.csv格式)。
要运行此程序,需要以下条件:
*数据库平台是MySQL,但也可以轻松地与SQL Server一起使用。喜欢MySQL Connector/NET的一点是,与数据库交互的语法几乎与MS SQL Server完全相同(例如,SqlCommand变为MySqlCommand)。
核心用例是检查文件夹及其子文件夹中的所有文件,并验证文件的校验和值是否未发生变化。如果发生变化,则通过电子邮件通知相关人员。程序还会报告文件总数、未更改文件数和新文件数。
程序的某些部分可以通过app.config文件进行配置,包括:
首先,需要一个数据库。附加的DRMC.sql文件可以恢复到MySQL中,或者可以在Notepad++中打开该文件,查看1个表、1个视图和5个存储过程。程序假设数据库名为"drmc"。
以下是如何连接到数据库并使用存储过程的示例:
        string m_conn = ConfigurationManager.ConnectionStrings["MySqlConnectionString"].ConnectionString;
        MySqlConnection conn = new MySqlConnection(m_conn);
        conn.Open();
        try
        {
            // 获取目录中所有文件的校验和和路径
            // 使用存储过程插入数据。记录结果和错误
            MySqlCommand cmd = new MySqlCommand("drmc.proc_checksum", conn);
            cmd.CommandType = CommandType.StoredProcedure;
            string[] m_files = Directory.GetFiles(m_path, "*.*", SearchOption.AllDirectories);
            foreach (string m_file in m_files)
            {
                string m_filename = Path.GetFileName(m_file);
                cmd.Parameters.Clear();
                cmd.Parameters.Add(new MySqlParameter("@M_FILEPATH", MySqlDbType.VarChar) { Value = m_file.Replace("\\", "\\\\") });
                cmd.Parameters.Add(new MySqlParameter("@M_FILENAME", MySqlDbType.VarChar) { Value = m_filename });
                cmd.Parameters.Add(new MySqlParameter("@M_SHA256", MySqlDbType.VarChar) { Value = GetChecksum(m_file).ToString() });
                cmd.ExecuteNonQuery();
                using (StreamWriter sw = File.AppendText(m_results))
                {
                    Logger.LogMessage("File " + m_file + " inserted in database.", sw);
                    sw.Close();
                }
            }
        }
    
以下是如何使用MySqlDataAdapter以及如何从ExecuteNonQuery获取OUT参数的示例:
        MySqlCommand cmd_newfiles = new MySqlCommand("drmc.proc_newfiles", conn);
        cmd_newfiles.CommandType = CommandType.StoredProcedure;
        cmd_newfiles.Parameters.AddWithValue("@M_NEWCOUNT", MySqlDbType.Int32);
        cmd_newfiles.Parameters["@M_NEWCOUNT"].Direction = ParameterDirection.Output;
        cmd_newfiles.ExecuteNonQuery();
        Console.WriteLine("New files: " + cmd_newfiles.Parameters["@M_NEWCOUNT"].Value);
        string str_newfiles = cmd_newfiles.Parameters["@M_NEWCOUNT"].Value.ToString();
        MySqlDataAdapter sda_newfiles = new MySqlDataAdapter(cmd_newfiles);
        DataSet ds_newfiles = new DataSet();
        ds_newfiles.DataSetName = "New Files";
        sda_newfiles.Fill(ds_newfiles);
        sda_newfiles.Dispose();
    
以下是如何构建电子邮件内容和附件的示例:
        DataTable dt_newfiles = ds_newfiles.Tables[0];
        DataTable dt_changedfiles = ds_changedfiles.Tables[0];
        DataTable dt_changedfiles1 = ds_changedfiles.Tables[1];
        FileGenerator.CreateFile(dt_changedfiles, m_changedfiles).ToString();
        string m_emailbody = "This e-mail is a summary of checksum file integrity for files located here: \r\n\r\n" + m_path + "\r\n\r\n";
        m_emailbody = m_emailbody + "There are a total of " + str_totalfiles + " files. \r\n\r\n";
        m_emailbody = m_emailbody + "The file location, file name, and checksum are the same for " + str_samefiles + " files. \r\n\r\n";
        m_emailbody = m_emailbody + "There are " + str_newfiles + " new files. These are listed below, if any.  Detailed information is in the attached file checksum_new_files.csv\r\n\r\n";
        m_emailbody = m_emailbody + "There are " + str_changedfiles + " files where the CHECKSUM HAS BEEN CHANGED. The integrity of the file is in doubt, or it has been changed by a user. The files are listed below, if any.  Detailed information is in the attached file checksum_changed_files.csv\r\n\r\n";
        string m_emailnewbody = "New Files: \r\n" + FileGenerator.CreateFile(dt_newfiles, m_newfiles).ToString();
        string m_emailchangedbody = "Changed Files: \r\n" + FileGenerator.CreateFile(dt_changedfiles1).ToString();
        m_emailbody = m_emailbody + m_emailnewbody + "\r\n" + m_emailchangedbody;
    
以下是如何配置和发送电子邮件的示例:
        var client = new SmtpClient("smtp.gmail.com", 587)
        {
            Credentials = new NetworkCredential("gmailuserhere", "gmailpasswordhere"),
            EnableSsl = true
        };
        MailMessage m_message = new MailMessage(m_notification_to, m_notification_from, m_notification_title + DateTime.Today.ToShortDateString(), m_emailbody);
        m_message.Attachments.Add(m_new_attachment);
        m_message.Attachments.Add(m_changed_attachment);
        client.Send(m_message);
    
        private static string GetChecksum(string m_fileinput)
        {
            try
            {
                string m_checksum;
                using (FileStream stream = File.OpenRead(m_fileinput))
                {
                    SHA256Managed sha = new SHA256Managed();
                    byte[] checksum = sha.ComputeHash(stream);
                    m_checksum = BitConverter.ToString(checksum).Replace("-", String.Empty);
                }
                return m_checksum;
            }
            catch (Exception ex)
            {
                using (StreamWriter swerr = File.AppendText(m_errors))
                {
                    Logger.LogMessage(ex.Message.ToString(), swerr);
                    swerr.Close();
                }
                return "unable to retrieve checksum";
            }
        }